【问题标题】:pygame both audial and visual sine wavepygame 音频和视频的正弦波
【发布时间】:2014-07-23 22:38:58
【问题描述】:

这是我程序中的一个函数,它在按下某个键时调用。应该发生的是按下键并播放相应的音符,并且屏幕上也会出现正弦波。声音播放良好,所以我不会再发布任何声音的代码,但它只是视觉方面的东西不起作用,为什么这波不显示?

WINDOWWIDTH = 640 # width of the program's window, in pixels
WINDOWHEIGHT = 480 # height in pixels
WIN_CENTERX = int(WINDOWWIDTH / 2) # the midpoint for the width of the window
WIN_CENTERY = int(WINDOWHEIGHT / 2) # the midpoint for the height of the window
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
fontObj = pygame.font.SysFont('freesansbold.ttf', 16)
FPSCLOCK = pygame.time.Clock()

# set up a bunch of constants
BLUE       = (  0,   0, 255)
WHITE      = (255, 255, 255)
DARKRED    = (128,   0,   0)
DARKBLUE   = (  0,   0, 128)
RED        = (255,   0,   0)
GREEN      = (  0, 255,   0)
DARKGREEN  = (  0, 128,   0)
YELLOW     = (255, 255,   0)
DARKYELLOW = (128, 128,   0)
BLACK      = (  0,   0,   0)

BGCOLOR = WHITE

FPS = 160 # frames per second to run at

pause = False


# making text Surface and Rect objects for various labels
sinLabelSurf = fontObj.render('sine', True, RED, BGCOLOR)
squareLabelSurf = fontObj.render('square', True, BLUE, BGCOLOR)

sinLabelRect = sinLabelSurf.get_rect()
squareLabelRect = squareLabelSurf.get_rect()

def MakeSineWave(freq=1000):
    #### visual part ####
    xPos = 0
    step = 0
    AMPLITUDE = 80 # how many pixels tall the waves with rise/fall.
    posRecord = {'sin': [], 'line': []}

    yPos = -1 * math.sin(step) * AMPLITUDE
    posRecord['sin'].append((int(xPos), int(yPos) + WIN_CENTERY))

    # draw the sine ball and label
    pygame.draw.circle(DISPLAYSURF, DARKRED, (int(xPos), int(yPos) + WIN_CENTERY), 10)
    sinLabelRect.center = (int(xPos), int(yPos) + WIN_CENTERY + 20)
    DISPLAYSURF.blit(sinLabelSurf, sinLabelRect)

    # draw the waves from the previously recorded ball positions
    for x, y in posRecord['sin']:
        pygame.draw.circle(DISPLAYSURF, DARKRED, (x, y), 4)

    # draw the border
    pygame.draw.rect(DISPLAYSURF, BLACK, (0, 0, WINDOWWIDTH, WINDOWHEIGHT), 1)

    pygame.display.update()
    FPSCLOCK.tick(FPS)

    if not pause:
        xPos += 0.5
        if xPos > WINDOWWIDTH:
            xPos = 0
            posRecord = {'sin': []}
            step = 0
        else:
            step += 0.008

    #### audial part ####
    return MakeSound(SineWave(freq))

【问题讨论】:

  • MakeSound 是立即返回还是等到声音播放完毕?或者,如果您根本不调用MakeSound,您的显示代码是否有效?首先你要确定你的错误在哪里,不在哪里。
  • makesound 会立即返回,或者它肯定会返回。我把return注释掉了,显示还是不显示
  • 我一定遗漏了一些东西,因为我没有看到任何可以实际绘制正弦曲线的特定代码。你有 posRecord 数据,但它似乎只包含一个元素。
  • 我正在尝试将此代码实现到我的预制音频代码中:inventwithpython.com/trig_waves.py
  • 该代码似乎与您在问题中发布的内容大不相同。您是说您在问题中发布的代码不是您实际使用的代码吗?

标签: python audio pygame trigonometry


【解决方案1】:

您只运行一次MakeSineWave - 当按下按钮时 - 但绘制波浪的代码必须在所有循环中一直运行。它在每个循环中绘制更长的波。

您似乎在另一个问题中询问如何绘制所有波浪并仅移动红球 - 并回答需要在 MakeSineWave 中进行不同的更改,然后针对此问题进行更改。


编辑:它是工作代码 - 但有一个混乱 - 它在主循环中直接需要更少的代码,但在一些新函数中需要更多的代码。

import pygame
from pygame.locals import *
import math
import numpy

#----------------------------------------------------------------------
# functions
#----------------------------------------------------------------------

def SineWave(freq=1000, volume=16000, length=1):

    num_steps = length * SAMPLE_RATE
    s = []

    for n in range(num_steps):
        value = int(math.sin(n * freq * (6.28318/SAMPLE_RATE) * length) * volume)
        s.append( [value, value] )

    return numpy.array(s)

#-------------------

def SquareWave(freq=1000, volume=100000, length=1):

    num_steps = length * SAMPLE_RATE
    s = []

    length_of_plateau = int( SAMPLE_RATE / (2*freq) )

    print num_steps, length_of_plateau

    counter = 0
    state = 1

    for n in range(num_steps):

        value = state * volume

        s.append( [value, value] )

        counter += 1

        if counter == length_of_plateau:
            counter = 0
            state *= -1

    return numpy.array(s)

#-------------------

def MakeSound(arr):
    return pygame.sndarray.make_sound(arr)

#-------------------

def MakeSquareWave(freq=1000):
    return MakeSound(SquareWave(freq))

#-------------------

def MakeSineWave(freq=1000):
    return MakeSound(SineWave(freq))

#-------------------

def DrawSineWave():

    # sine wave

    yPos = -1 * math.sin(step) * AMPLITUDE
    posRecord['sin'].append((int(xPos), int(yPos) + WIN_CENTERY))
    if showSine:
        # draw the sine ball and label
        pygame.draw.circle(screen, RED, (int(xPos), int(yPos) + WIN_CENTERY), 10)
        sinLabelRect.center = (int(xPos), int(yPos) + WIN_CENTERY + 20)
        screen.blit(sinLabelSurf, sinLabelRect)

    # draw the waves from the previously recorded ball positions
    if showSine:
        for x, y in posRecord['sin']:
            pygame.draw.circle(screen, DARKRED, (x, y), 4)


#-------------------

def DrawSquareWave():

    # square wave

    posRecord['square'].append((int(xPos), int(yPosSquare) + WIN_CENTERY))
    if showSquare:
        # draw the square ball and label
        pygame.draw.circle(screen, GREEN, (int(xPos), int(yPosSquare) + WIN_CENTERY), 10)
        squareLabelRect.center = (int(xPos), int(yPosSquare) + WIN_CENTERY + 20)
        screen.blit(squareLabelSurf, squareLabelRect)

    # draw the waves from the previously recorded ball positions
    if showSquare:
        for x, y in posRecord['square']:
            pygame.draw.circle(screen, BLUE, (x, y), 4)

#----------------------------------------------------------------------
# constants - (uppercase name)
#----------------------------------------------------------------------

# set up a bunch of constants
WHITE      = (255, 255, 255)
DARKRED    = (128,   0,   0)
RED        = (255,   0,   0)
BLACK      = (  0,   0,   0)
GREEN      = (  0, 255,   0)
BLUE       = (  0,   0, 255)

BGCOLOR = WHITE

WINDOWWIDTH = 1200 # width of the program's window, in pixels
WINDOWHEIGHT = 720 # height in pixels

WIN_CENTERX = int(WINDOWWIDTH / 2) # the midpoint for the width of the window
WIN_CENTERY = int(WINDOWHEIGHT / 2) # the midpoint for the height of the window

FPS = 160 # frames per second to run at

AMPLITUDE = 80 # how many pixels tall the waves with rise/fall.

#-------------------

SAMPLE_RATE = 22050 ## This many array entries == 1 second of sound.

SINE_WAVE_TYPE = 'Sine'
SQUARE_WAVE_TYPE = 'Square'

#----------------------------------------------------------------------
# main program
#----------------------------------------------------------------------

#-------------------
# variables (which don't depend on pygame)
#-------------------

sound_types = {SINE_WAVE_TYPE:SQUARE_WAVE_TYPE, SQUARE_WAVE_TYPE:SINE_WAVE_TYPE}

current_type = SINE_WAVE_TYPE
current_played = { 'z': None, 'c': None }
current_drawn = None

#-------------------

# variables that track visibility modes
showSine = True
showSquare = True

xPos = 0
step = 0 # the current input f

posRecord = {'sin': [], 'square': []} # keeps track of the ball positions for drawing the waves

yPosSquare = AMPLITUDE # starting position

#-------------------
# start program
#-------------------

pygame.init()

screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), pygame.HWSURFACE | pygame.DOUBLEBUF)
pygame.display.set_caption('Nibbles!')

# making text Surface and Rect objects for various labels

pygame.display.set_caption('Trig Waves')
fontObj = pygame.font.Font('freesansbold.ttf', 16)

### HERE 
squareLabelSurf = fontObj.render('square', True, BLUE, BGCOLOR)
squareLabelRect = squareLabelSurf.get_rect()

sinLabelSurf = fontObj.render('sine', True, RED, BGCOLOR)
sinLabelRect = sinLabelSurf.get_rect()

#-------------------
# mainloop
#-------------------

fps_clock = pygame.time.Clock()

_running = True

while _running:

    #-------------------
    # events
    #-------------------

    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            _running = False

        # some keys don't depend on `current_type`

        elif event.type == KEYDOWN:

            if event.key == K_ESCAPE:
                _running = False

            if event.key == K_RETURN:
                current_type = sound_types[current_type]  #Toggle
                print 'new type:', current_type

        # some keys depend on `current_type`

        if current_type == SINE_WAVE_TYPE:

            if event.type == KEYDOWN:

                #lower notes DOWN

                if event.key == K_z:
                    print current_type, 130.81
                    current_played['z'] = MakeSineWave(130.81)
                    current_played['z'].play()
                    current_drawn = DrawSineWave

                elif event.key == K_c:
                    print current_type, 180.81
                    current_played['c'] = MakeSineWave(180.81)
                    current_played['c'].play()
                    current_drawn = DrawSineWave

            elif event.type == KEYUP:

                #lower notes UP

                if event.key == K_z:
                    current_played['z'].fadeout(350)
                    current_drawn = None

                    #sine - reset data
                    xPos = 0
                    posRecord['sin'] = []
                    step = 0

                elif event.key == K_c:
                    current_played['c'].fadeout(350)
                    current_drawn = None

                    #sine - reset data
                    xPos = 0
                    posRecord['sin'] = []
                    step = 0

        elif current_type == SQUARE_WAVE_TYPE:

            if event.type == KEYDOWN:

                #lower notes DOWN

                if event.key == K_z:
                    print current_type, 130.81
                    current_played['z'] = MakeSquareWave(130.81)
                    current_played['z'].play()
                    current_drawn = DrawSquareWave

                elif event.key == K_c:
                    print current_type, 180.81
                    current_played['c'] = MakeSquareWave(180.81)
                    current_played['c'].play()
                    current_drawn = DrawSquareWave

            elif event.type == KEYUP:

                #lower notes UP

                if event.key == K_z:
                    current_played['z'].fadeout(350)
                    current_drawn = None

                    # square - reset data
                    xPos = 0
                    yPosSquare = AMPLITUDE
                    posRecord['square'] = []
                    step = 0

                elif event.key == K_c:
                    current_played['c'].fadeout(350)
                    current_drawn = None

                    # square - reset data
                    xPos = 0
                    yPosSquare = AMPLITUDE
                    posRecord['square'] = []
                    step = 0

    #-------------------
    # draws
    #-------------------

    # fill the screen to draw from a blank state
    screen.fill(BGCOLOR)

    if current_drawn:
        current_drawn()

    pygame.display.update()

    #-------------------
    # moves
    #-------------------

    if current_drawn:
        xPos += 1.0 #0.5

        if xPos > WINDOWWIDTH:
            #sine ### HERE
            xPos = 0
            posRecord['sin'] = []
            step = 0

            # square ### HERE
            yPosSquare = AMPLITUDE
            posRecord['square'] = []
        else:
            #sine ### HERE
            step += 0.008
            #step %= 2 * math.pi

            # square ### HERE
            # jump top and bottom every 100 pixels
            if xPos % 100 == 0:
                yPosSquare *= -1
                # add vertical line
                for x in range(-AMPLITUDE, AMPLITUDE):
                    posRecord['square'].append((int(xPos), int(x) + WIN_CENTERY))

    #-------------------
    # FPS
    #-------------------

    fps_clock.tick(FPS)

#-------------------
# end program
#-------------------

pygame.quit()

#----------------------------------------------------------------------

【讨论】:

  • 这太好了,非常感谢你,再次证明你是一个很大的帮助:)
  • 这里有一个基本概念,那就是 Pygame 文档对于生成的声音没有足够的文档。音频教程假定您将导入 .WAV 音效,并且不迎合以编程方式生成音调/声音的概念。我这么说是因为我已经查看了 Pygame 文档和示例以获取此类示例,并且通过谷歌搜索,我在这里找到了这个很好的示例。谢谢@furas。
猜你喜欢
  • 2011-07-03
  • 1970-01-01
  • 1970-01-01
  • 2015-12-16
  • 2023-04-06
  • 1970-01-01
  • 2015-05-21
  • 2012-09-03
  • 2013-01-06
相关资源
最近更新 更多