PDA

View Full Version : playing sound and displaying picture - condition within loop


jelly
02-04-2016, 07:47 AM
Dear all,

I am a programming beginner and I started using Vizard because I am trying to design a little experiment for my studies. Here is what is supposed to happen and below is what I have so far:

The screen should show an upper and a lower window. Each window will receive a simple texture (.png or .jpeg) to display two different pictures. In the upper window, there would be the task instruction and in the lower window, there would be a "default" picture. At the same time, a beep sound will play 10 times at random intervals (from 1 to 4 seconds). What I want: 7 out of ten random times, just as a sound cue plays, the lower screen should change from the default picture to Picture A and 3 out of 10 random times to Picture B.


#Set background colour to white:
viz.clearcolor(viz.WHITE)

taskpic = 'instruction.jpg'
pictureA = 'picA.jpg'
pictureB = 'picB.jpg'
picturedefault = 'default.png'
cue = viz.addAudio('dong.wav')
SoundDuration = cue.getDuration()

import viz
import time
import viztask
import random
viz.go()

def exp(): #this is the function that triggers my experiment

screen2 = viz.addTexQuad(size=0.5) #upper screen window
screen2.setPosition([0,2.1,1.3])
screen2.setSize([0.4, 0.4])

screen3 = viz.addTexQuad(size=0.5) #lower screen window
screen3.setPosition([0,1.6,1.3])
screen3.setSize([0.4, 0.4])

picture_task = viz.add(taskpic)
defaultpic = viz.add(default)

screen2.texture(picture_task) #picture with instruction is added as a texture to upper screen
screen3.texture(defaultpic) #default picture is added as a texture to upper screen

def playCueLoop():
count = 0
while count < 10:
count += 1
for x in count:
if x <= 7:
cue.play()
yield viztask.waitTime(SoundDuration+random.randrange(1, 4))
cue.stop()
PicA = viz.add(PictureA)
screen3.texture(PicA)
yield viztask.waitTime()
elif x <= 3:
cue.play()
yield viztask.waitTime(SoundDuration+random.randrange(1, 4))
cue.stop()
PicB = viz.add(PictureB)
screen3.texture(PicB)
yield viztask.waitTime()

#viztask.schedule(playCueLoop)

viztask.schedule(exp)



I know there must be a lot of things wrong in this code (apart from the if statement - maybe the rationale behind the changing of the screen windows?), but it sort of worked until I had the if condition (7 and 3 out of 10). I've played around with it and sometimes I still get the sound to play, but at no point have I managed to change the lower screen, even without a complex condition attached to it.

I would be happy to receive some pointers in the right direction! At the moment there are probably a lot of things to improve and it is impossible for me to isolate one aspect to test it around.

Thank you very much in advance for your help! :)

Jeff
02-04-2016, 11:47 PM
In general, debugging custom code is beyond the scope of what we can help with on the forum. When posting code it's best to create the simplest possible example that can be run directly and reproduces the issue. See the guidelines for posting Vizard code (http://forum.worldviz.com/faq.php?faq=vb3_reading_posting#faq_faq_vizard_cod e) for more information.

Erikvdb
02-05-2016, 01:30 AM
I agree with Jeff that we shouldn't fix entire programs here, and there is indeed a lot wrong with your code :p

The main issue here is that your for loop inside the while loop makes absolutely no sense and your "x <= 3" will never trigger because if x is smaller than 3, it's also smaller than 7.
For a proper random chance calculation (with a given chance), use something like:
if random.random() < 0.7
Or if you want to make sure that it is always going to be exactly 7 out of 10, make a list with 7 "A"s and 3 "B"s, random.shuffle() the list and iterate over that.

jelly
02-06-2016, 01:51 PM
Thanks! I have made some advancements yesterday, now at least the logic with the changing the screen works. My next step is that loop so thanks for the useful pointers. I'll post an update soon. :)

jelly
02-07-2016, 10:08 AM
Hello again!

I got the lower window exchange to work. That alone taught me some things about global variables and how to think about those TexQuads. Now on to the next problem: Exchanging the picture in the lower window 7 out of 10 times with one picture and 3 times with another (randomly).

I tried the list strategy, as suggested by Erikvdb, I've consulted all my resources, and I managed to implement it. However, the problem is that sometimes it shows the picture C 3 random times (as it should), other times, only 1 or 2 times. Almost as if it's randomly picking from the list 10 times. However, I want it to go through the entire list once. I am wondering if my list implementation is correct? Maybe I should not put several identical elements in a list? Or it's a problem regarding the implementation inside the "while loop"

I tried to simplify the code and create this as a separate script with the simplest form of the issue, as suggested by Jeff. Rather than code debugging I am hoping that someone might link me to a relevant example of a list within a loop. Obviously I am lacking the logic behind it especially when things get nested.



## Import Vizard modules ##

import viz
import viztask
import random

#Start Vizard:
viz.go()

## STIMULI ##

#pictures
pictureA = viz.add('picA.jpg')
default = viz.add('default.png')

#sound
cue = viz.addAudio('dong.wav')

#list (7 times picture B and 3 times picture C)
pictureList = ['picB.png', 'picB.png', 'picB.png', 'picB.png', 'picB.png', 'picB.png', 'picC.png', 'picC.png', 'picC.png']


#Make a screen window:
screen1 = viz.addTexQuad(size=0.5)
screen1.setPosition([0,2.1,1.3])
screen1.setSize([0.4, 0.4])

#Make a second screen window:
screen2 = viz.addTexQuad(size=0.5)
screen2.setPosition([0,1.6,1.3])
screen2.setSize([0.4, 0.4])

## TASK##

def task():
screen1.texture(pictureA)
screen2.texture(default)

def playCueLoop(): # default picture is shown in lower window + 10 times, at randomly intersperced intervals, a sound beep plays & each time that happens, the lower window replaces the default picture randomly with 7 times picB and 3 times pic C
count = 0
while count < 10:
count += 1
cue.play()
pictureIndex = 0
random.shuffle(pictureList)
picture = viz.add(pictureList[pictureIndex])
screen2.texture(picture)
pictureIndex += 1
yield viztask.waitTime(0.5)
screen2.texture(default)
yield viztask.waitTime(0)
yield viztask.waitTime(random.randrange(1,4))
viztask.schedule (playCueLoop())

viztask.schedule(task())


My only resource is a huge code with one list example (but there is no loop) - this is just a snippet:


photoList = ['A1.jpg','A2.jpg','A3.jpg','A4.jpg','A5.jpg','A6.j pg','A7.jpg','A8.jpg','A9.jpg','A10.jpg']
random.shuffle(photoList)

photo = viz.add('Pictures\\' + photoList[photoIndex])
photoFrame.texture(photo)
photoIndex += 1


I would be very greatful for any help or pointers!

P.S. I know Erikvdb suggested in another thread to stop the sound as well, however I left that out for now, to simplify the code :)

Erikvdb
02-11-2016, 05:33 AM
Only shuffle once, BEFORE the loop, not INSIDE the loop. Now the list gets constantly shuffled again before every pick :D

Also not crucial, but a helpful little housekeeping:
- use a for loop to iterate over the list. It's cleaner and easier.
- load your textures beforehand, not inside the loop, to improve performance.

jelly
02-11-2016, 10:13 AM
turns out it happened because the shuffling was done inside the while loop. the index should be a global variable as well. it now works!

jelly
02-11-2016, 10:14 AM
Oh Erikvdb, I had not seen your answer! Great, thank you, I will try the "for loop", that I have not implemented yet and I do want my code to become cleaner! Thanks!

jelly
02-15-2016, 09:26 AM
Hello again,

I hope I managed to implement what you meant, Erikvdb. I changed the while loop with a for loop and I loaded two of the screen textures outside of the loop, however, some textures I need to leave inside the loop, because it won't work otherwise. The screen 2 which is changing its picture, for example. I also tried adding the "picture = viz.add(pictureList[pictureIndex])" right after the pictureList and shuffling bit, but it won't work, it seems to want to be in the loop.

I did not really understand why I have to make the PictureIndex a global variable within the function, since I have defined it outside the function (which to my understanding already makes it a global variable), but it won't work otherwise. :)



import viz
import viztask
import random

#Start Vizard:
viz.go()

## STIMULI ##

#pictures
pictureA = viz.add('picA.jpg')
default = viz.add('default.png')

#sound
cue = viz.addAudio('dong.wav')

#list (7 times picture B and 3 times picture C)
pictureList = ['picB.png', 'picB.png', 'picB.png', 'picB.png', 'picB.png', 'picB.png', 'picB.png', 'picC.png', 'picC.png', 'picC.png']
random.shuffle(pictureList)
pictureIndex = 0

#Make a screen window:
screen1 = viz.addTexQuad(size=0.5)
screen1.setPosition([0,2.1,1.3])
screen1.setSize([0.4, 0.4])

#Make a second screen window:
screen2 = viz.addTexQuad(size=0.5)
screen2.setPosition([0,1.6,1.3])
screen2.setSize([0.4, 0.4])

screen1.texture(pictureA)
screen2.texture(default)

## TASK##

def task():
screen1
screen2

def playCueLoop(): # default picture is shown in lower window + 10 times, at randomly intersperced intervals, a sound beep plays & each time that happens, the lower window replaces the default picture randomly with 7 times picB and 3 times pic C
global pictureIndex
for x in range(10):
cue.play()
yield viztask.waitTime(random.randrange(1,4))
picture = viz.add(pictureList[pictureIndex])
screen2.texture(picture)
pictureIndex += 1
yield viztask.waitTime(0.5)
screen2.texture(default)
yield viztask.waitTime(0)
viztask.schedule (playCueLoop())

viztask.schedule(task())