COS 126 Class Meeting...The Queue abstract data type • A RingBuffer is a queue with a given capacity. • A queue is a data structure that allows the user to store elements by calling

Post on 15-Jul-2020

1 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

Transcript

COS 126 Class Meeting

November 8th, 2019Dr. Jérémie Lumbroso

lumbroso@cs.princeton.edu

Agenda for today

1. Debrief on LFSR

2. Overview of Guitar Hero

3. RingBuffer

4. GuitarString

5. From GuitarHeroLite (provided) to GuitarHero

Live Questions on Sli.do• QUESTIONS ARE WELCOME

during this class meeting

• Go to https://sli.do

• Enter meeting code: #5904

• You can:

• ASK your own questions

• UPVOTE questions you are interested in hearing the answer of

• Will try to monitor and select questions

• Please be kind!

Debrief on LFSRWILL BE RELEASED THURSDAY EVENING

Some Statistics

~1/4 of students

~3/4 of students

- Some used String.substring

- Others had string concatenation

quadratic performance

WILL BE RELEASED THURSDAY EVENING

Style comments from LFSR1. Many students (at least 78) hard-coded certain constants,

such as 8 in lfsr.generate(8)

• Better instead to define a constant:private final static int NUM_BITS = 8;

• We will start deducting next week2. When an instance variable is only assigned once (either in

declaration or in constructor) and never again, we can use the Java keyword final to indicate this—and Java warn us if we accidentally change the value

3. Use Character.getNumericValue(x) or (x - '0') to get "numeric" value of character

Please provide feedback

• We are currently exploring new and more efficient ways to write better rubrics

• We really would appreciate feedback on:

• the quality of explanations

• the usefulness to your programming skill growth

Better testing in main()• In main(), you want to call all the methods you have

implemented, to make sure they do not crash

• But that is not enough!

• You should also "test" whether a sequence of operations produces the result you expect

LFSR lfsr2 = new LFSR("01101000010", 9);

assert(lfsr2.generate(5) !== 25); assert(lfsr2.generate(5) !== 4); assert(lfsr2.generate(5) !== 30); assert(lfsr2.generate(5) !== 27);

assert(<expression>) will raise an error if the <expression> evaluates to false; it will do nothing if <expression> evaluates to true

Tests should include expected result

• assert(<expression>) will raise an error if the <expression> evaluates to false; it will do nothing if <expression> evaluates to true

• Alternatively, you can print out the output you get AND the value you expect:

To enable assert in jshell, use jshell -R -ea

LFSR lfsr2 = new LFSR("01101000010", 9);

StdOut.println(lfsr2.generate(5) + " should be 25"); StdOut.println(lfsr2.generate(5) + " should be 4"); StdOut.println(lfsr2.generate(5) + " should be 30"); StdOut.println(lfsr2.generate(5) + " should be 27");

LFSR lfsr2 = new LFSR("01101000010", 9);

assert(lfsr2.generate(5) !== 25); assert(lfsr2.generate(5) !== 4); assert(lfsr2.generate(5) !== 30); assert(lfsr2.generate(5) !== 27);

Guitar Hero Overview

What is the assignment • Simulate the vibration of a string,

and produce actual sound wave

• Create an actual digital instrument

• Deepen your understand of classes in Java

Overview• RingBuffer is your first classic data structure, a queue.

• Each GuitarString uses 1 RingBuffer.

• GuitarHero uses 37 GuitarStrings.

GuitarString RingBuffer

GuitarString RingBuffer

GuitarString RingBuffer

GuitarString RingBuffer

GuitarHero

(imagine 37strings)

What You Need To Know• Further practice of OOP programming and how to

combine multiple classes together

• Introduction + application of one possible implementation of the abstract Queue data type

• Implement complex abstractions

• RingBuffer implements a "circular buffer" by using a modulo wrap-around

• Using first, last and size to maintain "state"

• Implement an event-loop for a real-time program

You can now partner• You can work with a partner—in your

precept or another

• There is a partnering policy you should review

• Essentially both partners need to be present for any work on the code to take place

• Video-conferencing (and screen-sharing) is an acceptable substitute to in-person

• Create a group on TigerFile

• Pair programming is actually an industry practice

Reminder: Live Questions• QUESTIONS ARE WELCOME

during this class meeting

• Go to https://sli.do

• Enter meeting code: #5904

• You can:

• ASK your own questions

• UPVOTE questions you are interested in hearing the answer of

• Will try to monitor and select questions

• Please be kind!

RingBuffer

The Queue abstract data type

• A RingBuffer is a queue with a given capacity.

• A queue is a data structure that allows the user to store elements by calling enqueue() and returns them in the same order when the user calls dequeue().

• Queues are typically implemented with linked lists—which allows them to grow to any size. Both topics covered next week.

dequeue()

BACK FRONT

enqueue()

FIFO = First In First Out

A RingBuffer Example

• Initially an double[] array is created to store the RingBuffer; the length of this array is also called capacity = 6

• All the values are 0.0

• first and last are set to 0

• size is set to 0

01

2

34

5

0 1 2 3 4 5

0.0

0.0

0.0

0.0

0.0

0.0

0.0 0.0 0.0 0.0 0.0 0.0

A) first

last

first

last

RingBuffer rb = new RingBuffer(6);

size = 0

What you will implement

What the "abstraction" is

capacity

0 1

2

34

5

0 1 2 3 4 5

0.40

0.0

0.0

0.0

0.0

0.0

0.40 0.0 0.0 0.0 0.0 0.0

B) first

last

first

last

0 1

2

34

5

0 1 2 3 4 5

0.40

0.72

0.0

0.0

0.0

0.0

0.40 0.72 0.0 0.0 0.0 0.0

C) first

last

first

last

0 1

2

34

5

0 1 2 3 4 5

0.40

0.72

0.3

0.0

0.0

0.0

0.40 0.72 0.3 0.0 0.0 0.0

D) first

last

first

last

01

2

34

5

0 1 2 3 4 5

0.40

0.72

0.3

0.0

0.0

0.0

0.40 0.72 0.3 0.0 0.0 0.0

E)first

last

first

last

01

2

34

5

0 1 2 3 4 5

0.40

0.72

0.3

0.11

0.0

0.0

0.40 0.72 0.3 0.11 0.0 0.0

F)first

last

first

last

rb.enqueue(0.4) rb.enqueue(0.72) rb.enqueue(0.3)

rb.dequeue() !!--> 0.40

01

2

34

5

0 1 2 3 4 5

0.40

0.72

0.3

0.11

0.0

0.0

0.40 0.72 0.3 0.11 0.0 0.0

G)

firstlast

first

last

rb.dequeue() !!--> 0.72rb.enqueue(0.11)

size = 1 size = 2 size = 3

size = 2 size = 3 size = 2

The peek() operation

• The peek() operation provides the same output that dequeue() would, but unlike dequeue() it does not change the RingBuffer

01

2

34

5

0 1 2 3 4 5

0.40

0.72

0.3

0.11

0.0

0.0

0.40 0.72 0.3 0.11 0.0 0.0

G)

firstlast

first

last

rb.dequeue() !!--> 0.3size = 2

0 1

2

34

5

0 1 2 3 4 5

0.40

0.72

0.3

0.11

0.0

0.0

0.40 0.72 0.3 0.11 0.0 0.0

H1)

firstlast

first

last

size = 2

0 1

2

34

5

0 1 2 3 4 5

0.40

0.72

0.3

0.11

0.0

0.0

0.40 0.72 0.3 0.11 0.0 0.0

H2)

first

last

first

last

size = 1

rb.peek() !!--> 0.3

peek()

dequeue()

Note: capacity = 6

The wrap-around• Eventually, if we continue adding values, first and last will wrap

around the array

• Use modulo % and the capacity to do this

• Example below after adding 0.8, showing wrap around

0 1

2

34

5

0 1 2 3 4 5

0.40

0.72

0.3

0.11

0.8

0.0

0.40 0.72 0.3 0.11 0.8 0.0

first

last

first

last

size = 30 1

2

34

5

0 1 2 3 4 5

0.40

0.72

0.3

0.11

0.8

0.27

0.40 0.72 0.3 0.11 0.8 0.27

first

last

first

last

size = 4

Note: capacity = 6

rb.enqueue(0.27)rb.enqueue(0.8)H3) I)

String representation of RingBuffer (optional but helpful)• Having a good string representation for toString() of your

RingBuffer might be helpful to debug.

• Typically try to display IV in a useful way

• What values are in the buffer?

• Where are first and last?

• Maybe even size and/or capacity?

first last ------------------------------------------------ | 0.40 !|| 0.72 !|| 0.30 !|| 0.11 !|| !|| | ------------------------------------------------ 0 1 2 3 4 5

My string representation

in action

Pitfalls• The capacity never changes; it's the length of the underlying array

that is allocated in the constructor of RingBuffer

• Do not try to compute the size; just:

• Increment the size by 1 when you enqueue()

• Decrease the size by 1 when you dequeue()

• And make sure every time it is about to change that

• The size does not become negative

• The size does not grow beyond the capacity

• Remember that the array can be filled with "ghost" values (values that have been dequeued, but that have not yet been overwritten yet)

GuitarString

GuitarString

• GuitarString simulates the Karplus-Strong algorithm

• Produce initial "excitation" of the string

• Then simulate dampening as string oscillates (and produces sound)

• Different sizes of RingBuffer lead to different frequencies/notes

GuitarString RingBuffer

Two constructors• Two constructors: Both constructors must initialize all instance variables

•GuitarString(double frequency)

• "The first constructor creates a RingBuffer of the desired capacity n (the sampling rate 44,100 divided by the frequency, rounded up to the nearest integer), and initializes it to represent a guitar string at rest by enqueuing n zeros."

•GuitarString(double[] init)

• "The second constructor creates a RingBuffer of capacity equal to the length n of the array, and initializes the contents of the ring buffer to the corresponding values in the array. In this assignment, this constructor's main purpose is to facilitate testing and debugging."

Using RingBuffer

• How are you going to remove all items?

• How are you going to fill the RingBuffer with noise?

• How are you going to fill the RingBuffer with zeroes?

public class RingBuffer { public RingBuffer(int capacity) !// creates an empty ring buffer with the specified capacity public int capacity() !// returns the capacity of this ring buffer public int size() !// returns the number of items currently in this ring buffer public boolean isEmpty() !// is this ring buffer empty (size equals zero)? public boolean isFull() !// is this ring buffer full (size equals capacity)? public void enqueue(double x) !// adds item x to the end of this ring buffer public double dequeue() !// deletes and returns the item at the front of this ring buffer public double peek() !// returns the item at the front of this ring buffer

public static void main(String[] args) !// tests this class by directly calling all instance method }

tic()

• tic() simulates another time step of the sound wave we are calculating by:

• calculating the average of the front two elements

• multiply by DECAY_FACTOR (= 0.996)

• adding the result to the RingBuffer

• removing the first element (but not the second)

• How can you look at the second value (here .4) without removing it from RingBuffer?

From GuitarHeroLite to GuitarHero

From 2 to many

create an array+ use for-loop to initialize at right frequency

use the keyboardStr.indexOf(s) trick(see checklist) not 37-way if-statement

use for-loop to sum sample from all strings

use for-loop to call tic() for all strings

Questions?

top related