Laboration 3. Redovisning. Snabbkurs i digitalt ljud. Objektorienterad programmering

Relevanta dokument
Laboration 3: Musikbibliotek

Laboration 4. Redovisning Uppgifterna skall vara demonstrerade för och godkända av en handledare senast måndag 23/2.

Objektorienterad programmering. Fält som funktionsresultat. Mer om fält: att uppdatera ett parameterfält. Kontrast: Parametrar av primitiv typ

Dagens program. Programmeringsteknik och Matlab. Objektorienterad programmering. Vad är vitsen med att ha både metoder och data i objekten?

Lite om felhantering och Exceptions Mer om variabler och parametrar Fält (eng array) och klassen ArrayList.

Laboration 4: Digitala bilder

Tentamen, EDAA10 Programmering i Java

Föreläsning 3-4 Innehåll

Uppgiften är att beskriva en kvadrat i ett Java program. En första version av programmet skulle kunna se ut så här:

OOP Objekt-orienterad programmering

Objektorienterad programmering E. Telefonboken, än en gång. Gränssnitt. Telefonboken med gränssnitt specificerat, del 1.

1 Uppgift 1. a) Skapar ett Company-objekt med hjälp av den överlagrade konstruktorn. Du kan själv välja värden på instansvariablerna.

Tentamen OOP

LÖSNINGSFÖRSLAG Programmeringsteknik För Ing. - Java, 5p

Föreläsnings 9 - Exceptions, I/O

Objektorienterad Programmering (TDDC77)

Högskolan Dalarna sid 1 av 7 DI-institutionen Hans-Edy Mårtensson Sten Sundin

Outline. I Vi kan lätt göra samma sak för fyra variabler... I Hur gör vi för 400 inlästa värden? I Ofta behöver man flera likadana variabler

Föreläsning 3-4 Innehåll. Diskutera. Metod. Programexempel med metod

Instuderingsfrågor, del D

Föreläsning 5-6 Innehåll. Exempel på program med objekt. Exempel: kvadratobjekt. Objekt. Skapa och använda objekt Skriva egna klasser

TDDC77 Objektorienterad Programmering

Föreläsning 5-6 Innehåll

DUGGA: Objektorienterade applikationer. Läs detta! Uppgifterna är inte avsiktligt ordnade efter svårighetsgrad.

Objektorienterad programmering i Java I. Uppgifter: 2 Beräknad tid: 5-8 timmar (OBS! Endast ett labbtillfälle) Att läsa: kapitel 5 6

Lite mer om Javas stöd för fält. Programmering. Exempel: vad är det största talet? hh.se/db2004. Fält samt Input/Output

Programmering med Java. Grunderna. Programspråket Java. Programmering med Java. Källkodsexempel. Java API-exempel In- och utmatning.

Föreläsning 8 SLUMPTAL, SIMULERING + INTRODUKTION TILL VEKTORER

ID1004 Laboration 4, November 2012

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Felsökning. Datatyper. Referenstyper. Metoder / funktioner

Typkonvertering. Java versus C

ITK:P1 Föreläsning 1. Programmering. Programmeringsspråket Java. Stark typning Explicit typning Strukturerat Hög säkerhet

Introduktion till Datalogi DD1339. Föreläsning 2 22 sept 2014

Tentamen i EDAF oktober Skrivtid: Skriv bara på ena sidan av pappret tentorna kommer att scannas in, och endast framsidorna rättas.

Vem är vem på kursen. Objektorienterad programvaruutveckling GU (DIT011) Kursbok Cay Horstmann: Big Java 3rd edition.

Laboration 1. "kompilera"-ikonen "exekvera"-ikonen

DELPROV 1 I DATAVETENSKAP

DAT043 Objektorienterad Programmering

EDAA20 Programmering och databaser. Mål komprimerat se kursplanen för detaljer. Checklista. Föreläsning 1-2 Innehåll. Programmering.

Objektorienterad programmering D2

Laboration 1. Objektorienterad programmering, Z1. Syfte

Administrativt. Programmeringsteknik för I1. Dagens program. Objektorienterad programmering

TENTAMEN I PROGRAMMERING. På tentamen ges graderade betyg:. 3:a 24 poäng, 4:a 36 poäng och 5:a 48 poäng

(Man brukar säga att) Java är... Denna föreläsning. Kompilering av Java. Historik: Java. enkelt. baserat på C/C++ Allmänt om Java

Föreläsning 2. Täcker material från lektion 1, 2, 3 och 4:

DAT043 Objektorienterad programmering för D, DIT011 Objektorienterad programvaruutveckling för GU

Grundläggande programmering, STS 1, VT Sven Sandberg. Föreläsning 12

Programstruktur och terminologi. Programmet producerar följande utskrift i terminalfönstret: Ett Javaprogram består av en eller flera klasser

Föreläsning REPETITION & EXTENTA

Föreläsning 6: Metoder och fält (arrays)

JAVA Mer om klasser och objektorientering

Malmö högskola 2008/2009 CTS

Lite om reella tal. Programmering. I java. Om operatorers associativitet och prioritet

Java: Utvecklingsverktyg, datatyper, kontrollstrukturer

Algoritmer. Två gränssnitt

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Kort repetition. Programmeringsteknik för Bio1 och I1. Vad ska vi lära oss idag? Ett exempel

Föreläsning 2 Objektorienterad programmering DD1332. Typomvandling

Datatyper och kontrollstrukturer. Skansholm: Kapitel 2) De åtta primitiva typerna. Typ Innehåll Defaultvärde Storlek

Bankkonto - övning. Övning 2 Skriv en metod, geträntan, som returnerar räntan.

Chapter 3: Using Classes and Objects

Laboration 2. returnerar true om det är omöjligt för roboten att göra move() utan att. exekveringsfel erhålls, annars returnera false.

Chapter 4: Writing Classes/ Att skriva egna klasser.

Tentamen i Objektorienterad programmering

Laboration 3, uppgift En klass för en räknare

Datatyper. Programmering. Att definiera datatyper i Java. Laddade partiklar. (x,y) (Rx,Ry) hh.se/db2004

Det finns en referensbok (Java) hos vakten som du får gå fram och läsa men inte ta tillbaka till bänken.

Inledande programmering med C# (1DV402) Tärningarna ska kastas

Det är principer och idéer som är viktiga. Skriv så att du övertygar examinatorn om att du har förstått dessa även om detaljer kan vara felaktiga.

Kompilera och exekvera Javakod

1 Egna klasser. 1.1 En punkt-klass

Föreläsning 14. Filhantering

Innehållsförteckning. 9 Större projekt Övningsuppgifter...32

Att skriva till och läsa från terminalfönstret

Objektorientering: Lagring, räckvidd och livstid

Objektorienterad programmering i Java

TUTORIAL: SAMLING & KONSOLL

Översikt MERA JAVA OCH ECLIPSE. Uttryck och tilldelning. Uttryck och tilldelning. Uttryck och tilldelning. Uttryck och tilldelning

Objektorienterad programmering i Java Undantag Sven-Olof Nyström Uppsala Universitet Skansholm: Kapitel 11

Objektorienterad programmering Föreläsning 5

Grundläggande programmering DVG A08 & ISG A04. Allmän information. Å vem är jag då. Karlstads Universitet, Johan Öfverberg 1

Grundkurs i programmering, 6 hp (725G61) Dugga 2 tillfälle 2

EDAA20 Programmering och databaser. Mål komprimerat se kursplanen för detaljer. Om att lära sig programmera. Föreläsning 1-2 Innehåll.

Objektorienterad programmering i Java Undantag Sven-Olof Nyström Uppsala Universitet Skansholm: Kapitel 11

Lösningsförslag övning 2.

Grundläggande programmering med C# 7,5 högskolepoäng

EDAA20 Föreläsning Klassen ArrayList. Viktiga operationer på ArrayList. Generisk klass

Command line argumenter. Objektorienterad Programmering (TDDC77) Vad blir resultatet? Nu då? Ahmed Rezine. Hösttermin 2016

Objektorientering: Lagring och livstid

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 3 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Objektorienterad Programmering (TDDC77)

Föreläsning 2, vecka 8: Repetition

Idag. Javas datatyper, arrayer, referenssemantik. Arv, polymorfi, typregler, typkonvertering. Tänker inte säga nåt om det som är likadant som i C.

TDIU01 - Programmering i C++, grundkurs

Tentamen FYTA11 Javaprogrammering

Laboration 1. "kompilera"-ikonen "exekvera"-ikonen

OBJEKTORIENTERAD PROGRAMVARUUTVECKLING

Data och Information. Dr. Johan Hagelbäck.

Laboration 2. Objektorienterad programmering. Syfte

Transkript:

Laboration 3 Objektorienterad programmering Syfte I denna laboration ska ni definiera ett litet bibliotek för att generera musik som kan avlyssnas med vanliga musikprogram. Tiden medger inte något omfattande bibliotek, så den musik vi kan åstadkomma är begränsad. Syftet med denna laboration är att få övning i att använda en-dimensionella fält. Redovisning Lämna in samtliga källkodsfiler som en komprimerad zip-fil i Fire. Snabbkurs i digitalt ljud Ljud uppstår genom att en tryckvåg fortplantas genom luften; vi har alltså ett analogt fenomen. För behandling i datorer vill vi ha en digital representation av den analoga signalen. Vi betraktar följande figur: Den grå analoga signalen har samplats (avlästs) vid diskreta tidpunkter (de vertikala streckade linjerna). Dessutom har signalvärdena (amplituderna) vid dessa tidpunkter avrundats till närmaste heltalsvärde, representerat av de horisontella streckade linjerna. Den samplade digitala signalen är alltså i detta fall [0, 4, 5, 4, 3, 4, 6, 7, 5, 3, 3, 4, 4, 3]. En vanlig standard för digital musik, som används för CD-skivor, har samplingsfrekvensen 44100 Hz (dvs antalet avläsningar av signalen per sekund). Noggrannheten i amplitud är typiskt 16 bitar, dvs 2 16 = 65536 olika amplituder kan anges. I vårt bibliotek ska vi sampla signaler med denna frekvens, INSTITUTIONEN FÖR DATAVETENSKAP Chalmers Tekniska Högskola Besök: Rännvägen 6 Telefon: +46 (0)31-772 6154 E-post: alexg@chalmers.se Web: http://www.cse.chalmers.se/edu/course/tda540/

men representera amplituder med värden av typen double, skalade så att amplituden alltid ligger mellan -1 och 1. Först i sista steget, i en klass som ni får given, gör vi om till 16 bitars värden för amplituden. En lämplig datatyp för musik är alltså ett fält av flyttal, dvs double[]. Vi kan göra två observationer: Det mänskliga örat kan uppfatta ljud ungefär i intervallet 20-20000 Hz. Grundfrekvensen för ettstrukna A (den ton efter vilken instrument stäms) är 440 Hz. När en sinussignal med denna frekvens samplas med samplingsfrekvens 44.1 khz får man alltså med ca 100 värden per period, dvs den samplade signalen ger en mycket god bild av den analoga signalen. Nedan visas en period av en sinuskurva, samplad med 100 punkter. För högre frekvenser blir givetvis upplösningen sämre, men för hörbara signaler har man ändå minst två avläsningar per period. Om man sparar en digital signal i en fil med 16 bitar, dvs två bytes, per avläsning och 44100 avläsningar per sekund, så blir det 88 kbytes per sekund, dvs ca 5 Mbytes per minut. Och detta i mono; med två kanaler fördubblas filstorleken till 10 Mbytes per minut. Ljudfiler i detta format blir därför stora. Ofta använder man därför komprimerade format som MP3, vilka tappar en del ljudinformation men ger mycket mindre filer. Vi ska dock i denna laboration hålla oss till okomprimerade filer i formatet WAV. Tillhandahållna klasser Skapa en ny mapp för denna laboration och ladda ner zip-filen från kurshemsidan till denna mapp. Bekanta er sedan med det givna programmet. 1. Öppna filen Main.java i IntelliJ. Bygga projektet och kör programmet (med hörlurar på!). Ni hör en ren sinussignal med frekvensen 440 Hz i två sekunder, följt av en lika lång signal en oktav högre. 2. Titta på filen Main.java: import java.io.file; public class Main { public static void main(string[] args) { SoundDevice device = new SoundDevice(); Song song = new Song(5);

} song.add(sine(440, 2)); song.add(sine(880, 2)); song.play(device); song.save(device.getformat(), new File("twotones.wav")); public static double[] sine(double freq, double duration) { int n = (int) (duration * SoundDevice.SAMPLING_RATE); double[] a = new double[n]; double dx = 2 * Math.PI * freq / SoundDevice.SAMPLING_RATE; for (int i = 0; i < n; i++) { a[i] = Math.sin(i * dx); } } } return a; Vi börjar med att titta på metoden main. Först skapas två objekt, en SoundDevice och en Song: Klassen SoundDevice får ni given. Denna klass gör det möjligt att komma åt datorns ljudkort. Klassen Song, som ni också får given, används för att avbilda en sång. Klassen innehåller metoden add för att lägga till toner, metoden play för att spela sången, samt metoden save för att spara sången på en fil. Vi läser vidare i main. Två gånger lägger vi till toner genom att anropa song.add. Tonerna som läggs till är resultat av metoden sine (som definieras efter main). Metoden sine producerar en sinussignal med given frekvens och längd. Därefter spelas sången (vilket ni hörde) genom att anropa song.play. Med anropet song.save sparas slutligen sången på en fil med namnet "twotones.wav". (Filen kan öppnas och spelas upp med datorns musik-spelare (om en sådan finns). Gör detta och kolla att ni höra de två tonerna.) Vi är nu i en vanlig situation. Vi har fått ett program, provkört det, tittat på det och förstår en del av vad som pågår. Men en del är fortfarande konstigt. Vad betyder till exempel 5 i new Song(5)? 3. I underkatalogen doc finns dokumentation av de två klasserna Song och SoundDevice. Studera denna dokumentation och källkoden för de båda klasserna. Genom att läsa dokumentationen om Song bör ni kunna förstå vad femman betyder. För laborationen behöver vi inte förstå hur klassen SoundDevice är uppbyggd. Det räcker att se att konstanten SAMPLING_RATE = 44100 definieras i denna klass. 4. Det återstår att förstå funktionen sine som skapar och fyller ett fält med avläsningar av en ren sinusfunktion. Antalet värden i fältet är antalet avläsningar per sekund (SAMPLING_RATE) gånger tonens längd i sekunder (duration). Den funktion vi ska sampla är s(t) = sin(2πft), där f är frekvensen (som heter freq i metoden). Ska vi fylla fältet a med SAMPLING_RATE avläsningar av denna funktion så bör elementet med nummer i vara s(i/sampling_rate), eller sin(i * dx), där dx definieras som i koden ovan.

Uppgift 1: Ljudet av en sträng Nu är det dags att skapa ett musikaliskt intressantare ljud än en ren sinuston. Er uppgift är att definiera en metod: public static double[] pluck(double freq, double duration) som genererar en ton med den givna frekvensen och varaktigheten och som liknar ljudet då man knäpper på en sträng på ett stränginstrument. För detta finns en berömd metod: Karplus-Strongs algoritm, uppfunnen för cirka 30 år sedan. Notera att metoden pluck har samma parametrar som metoden sine, dvs tonens frekvens och varaktighet. Trots det kommer den att låta annorlunda. Börja med att skapa en ny klass MusicUtils (i en ny fil MusicUtils.java). Flytta dit sine från Main. När ni flyttat bort sine från klassen Main måste ni ändra användningen av den i metoden main; ni måste nu skriva MusicUtils.sine för att Java-kompilatorn ska hitta metoden. Gör det, kompilera om och kolla att ni fortfarande kan köra Main och höra de två sinustonerna. Ni ska nu lägga till pluck till klassen MusicUtils. Karplus-Strongs algoritm fungerar på följande sätt: 1. Först måste ni deklarera och skapa ett fält av flyttal av lämplig storlek på precis samma sätt som i funktionen sine. 2. Sedan ska ni fylla ni fältets element med värden. Detta görs i två steg: (a) Låt p vara antalet avläsningar per period, dvs samplingsfrekvensen 44100 dividerat med frekvensen freq för den önskade tonen. Fyll de första p elementen med slumptal i intervallet [ 1.0, 1.0]. För att få slumptal använder instansmetoden nextdouble() i klassen Random. Om ni tittar i API n, ser ni att metoden nextdouble() ger ett ett värde i intervallet [0.0, 1.0]; hur gör man om det till ett tal mellan -1 och 1? (b) Övriga element i fältet, elementen efter de p första elementen, beräknas på följande sätt: elementet med index i är summan av elementen med index och i - p i - (p - 1) multiplicerad med en dämpkonstant K. Ett lämpligt värde på K är 0.498, men ni får gärna experimentera med olika värden (som ger olika ljud). Intressanta ljud fås bara för K- värden litet mindre än 0.5. Testa er metod genom att ändra i main så att ni anropar pluck i stället för sine. Ändra också namnet på filen där ni sparar sången. Ni bör fortfarande höra två toner, men nu ska de låta som när man knäpper på en sträng. Vi kan nu se att koden i sine och pluck har samma struktur: vi deklarerar och skapar ett fält, fyller det med innehåll och returnerar det. Innehållet blir olika i de två fallen och vi får därför olika ljud när vi spelar upp filen.

Uppgift 2: Ett bättre sätt att ange toner Hittills har vi angett toner genom att ge frekvens och varaktighet. Vi vill nu närma oss hur toner anges normalt i musik, dvs med noter i en skala. Vi kan inte gå igenom musikteori här, utan nöjer oss med att konstatera att på till exempel en pianoklaviatur finns tolv tangenter per oktav, sju vita och fem svarta: Vi skall inte ange toner med de vanliga bokstäverna CDEFGAH, eftersom det kräver förtecken för de svarta tonerna och dessutom något sätt att ange oktav. Istället numrerar vi tonerna med heltal som på klaviaturen ovan, där ettstrukna A ges nummer 0 (vi väljer A som utgångspunkt, eftersom den, med frekvensen 440 Hz, oftast är referenspunkt för musikaliska skalor). Ettstrukna C är alltså -9, tvåstrukna C är 3, trestrukna C är 15, osv. Detta har också fördelen att vi lätt får en direkt formel för frekvensen för en given ton. Ton nummer k har frekvensen: 440 2 k 12 Hz Ettstrukna C har alltså frekvensen 440 2 9 12 = 261.63Hz. Er uppgift är nu att utöka MusicUtils med ytterligare en metod: public static double[] note(int pitch, double duration) som genererar en ton med givet nummer (anges med parametern pitch) och varaktighet (anges med parametern duration). Observera: Det enda man behöver göra är att räkna ut frekvensen från tonens nummer, anropa pluck för att få ett fält och returnera detta fält. I note ska man varken skapa eller fylla fältet; det sköter pluck om. När ni gjort detta kan ni testa resultatet genom att ändra i main så att programmet spelar till exempel början på Gubben Noak som ni hittar in figur 1. Valet av 0.4 sekunder per ton här är en smaksak; ni kan välja annat tempo om ni så önskar. Vi ser också att det blir mycket omständligt att beskriva musik på detta sätt. Men innan vi ger oss på att åtgärda detta ska vi förbättra ljudet ytterligare.

song.add(musicutils.note(-9, 0.4)); song.add(musicutils.note(-9, 0.4)); song.add(musicutils.note(-9, 0.4)); song.add(musicutils.note(-5, 0.4)); song.add(musicutils.note(-4, 0.4)); song.add(musicutils.note(-5, 0.4)); song.add(musicutils.note(-5, 0.4)); song.add(musicutils.note(-9, 1)); song.play(device); Figur 1: Gubben Noak Uppgift 3: Att blanda ljud Ett betydligt intressantare ljud fås om vi spelar flera toner samtidigt. Som ett första steg ska ni skriva en metod: public static double[] average(double[] t1, double[] t2) som genererar ett medelvärde av tonerna t1 och t2. Vi förutsätter också att de två tonerna har samma varaktighet så att fälten är lika långa. Metoden average ska helt enkelt skapa ett nytt fält och för varje index ta medelvärdet av motsvarande värden i t1 och t2. Nästa steg är att ni skall skriva en metod: public static double[] harmonic(int pitch, double duration) som skapar en ton med givet nummer och varaktighet genom att blanda tre toner som skapats med note, nämligen tonerna med nummer pitch, pitch-12 och pitch+12 (dvs också de två tonerna en oktav under och över den avsedda). Förslagsvis blandas först de två sistnämnda tonerna med metoden average och sedan blandas resultatet med den första tonen, återigen med metoden average. Slutligen kan ni testa resultatet genom att i main ersätta alla note med harmonic. När ni kommit så här långt har ni definierat en biblioteksklass MusicUtils som innehåller fem funktioner: sine som ni fick given samt pluck, note, average och harmonic som ni definierat själva.

Uppgift 4: Att separera sånger från programmet I main ovan var beskrivningen av Gubben Noak en del av programmet. Mycket bättre är att spara beskrivningen av sången i en fil noak.txt som börjar -9 0.4-9 0.4-9 0.4-5 0.4-4 0.4-5 0.4-5 0.4-9 0.4 och sedan låta programmet läsa denna fil och med hjälp av informationen på varje rad skapa en ton som läggs till sången. Ännu bättre är kanske att ändra varaktigheten för tonerna i filen till 0.25, svarande mot en kvartston, och sedan separat ange tempot. Ändra nu main så att en sångbeskrivning läses från en fil genom att ge filnamnet som argument till main-metoden. Koppla sedan filen till ett Scanner-objekt. Detta görs på följande vis: public static void main(string[] args) throws FileNotFoundException { Scanner sc = new Scanner(new File(args[0]));... } Klassen Scanner har en konstruktor som göra att Scanner-objektet läser data från en fil. En fil handhas som ett objekt av klassen File och klassen File har en konstruktor vars parameter är namnet på den fysiska filen. Vid anropet av new File(arg[0]) inträffar en exception av typen FileNotFoundException om den angivna fysiska filen inte finns. FileNotFoundException tillhör en typ av exceptions som måste tas hand om eller kastas vidare. Här kastar vi FileNotFoundException vidare, därav står det throws FileNotFoundException i metodhuvudet till main-metoden. I er katalog finns också en fil elise.txt som ni kan använda för testning, om ni inte vill skriva en egen fil för någon musik ni föredrar. Denna fil utnyttjar ovan antydda förbättring; varaktigheten 0.125 betyder en åttondelston. Om man låter detta vara synonymt med varaktigheten hos tonen i sekunder så blir det alldeles för högt tempo. Om en åttondel varar i 0.125 sekunder så hinner man 240 fjärdedelsnoter på en minut; 148 fjärdedelar per minut är mer lagom. En möjlighet är att även ange tempot som argument till main-metoden. Gör det!

Slutkommentarer Förhoppningsvis har ni nu lärt er en del programmering med fält och en del om digital audio. Avslutningsvis skall påpekas att vi i ett avseende gjort det enkelt för oss: vi har slösat med minne. Vi skapar många och långa fält också för korta ljudsekvenser. Det går att göra det vi gjort, och mer, med mycket mindre minneskonsumtion. För ett allvarligt menat musikprogram måste man vara mer ekonomisk, men för vårt syfte här lämpar sig en mer frikostig attityd till minnesförbrukning bättre.