Version 19, last updated by tjac0 at Jun 03 01:21 2009 UTC

Software Design Specification

Module Summary

Diagrams

General Architecture

E/R Diagram

  • This diagram maps the relationships between entities.

Data and Control Flow Diagram

  • This diagram shows the relations between the various modules and data structures in the architecture. It clearly shows what the functional parts of the architecture are, and what parts are static.

Major Modules and Interfaces

GUI

Interface

  • RRGuiMain.__init__(self) - creates the main GUI coordinator and initializes certain variables. Only one coordinator should be created per runtime. Throws a RuntimeError if called more than once.
  • RRGuiMain.run(self) - Creates all GUI widgets and enters the Qt event loop on the current thread. Returns when the Qt event loop ends, which is when the program should clean up and exit.
  • Interfaces with the CoreController. All method calls going to the CoreController occur on the Qt event thread, so to ensure a responsive interface the calls must return quickly.

References

  • Controller

Controller

  • The Controller is responsible for updating the application based on User actions.
  • Provides Qt callback functions for each Widget known as slots, which are triggered by signals.
  • If the signal denotes a change in the model, the controller will call the interface method of the appropriate class.

Interface

  • AddMusician() -- passes a musician to the Conductor, who adds it to the Ensemble.
  • RemoveMusician() -- passes a musician to the Conductor, who removes it from the Ensemble.
  • FilterMusicians(tags) -- references MusicianDirectory, and gets a list of Musicians with descriptions matching the given tags.
  • Play() -- Starts the CoreDriver, which causes audio to play.
  • Pause() -- Stops CoreDriver, which stops triggering audio playback.
  • UpdateSongInfo() -- Changes a value of SongInfo, such as the Key.
  • SetTempo(bpm) -- Changes the overall speed of the song playback.

References

  • MusicianDirectory
  • Conductor
  • Metronome
  • SongInfo

CoreDriver

  • Metronome

  • The Metronome is thread responsible for synchronizing the Conductor and the Parser.
  • It contains a timer which ticks on intervals which evenly divide a song measure into rhythmic units.
  • The Conductor and Parser listen for these ticks to increment the current position in the Score.
  • The Metronome implements the Play/Pause functionality: if it stops emitting ticks, the Conductor and Parser do not do anything.

Interface

  • Run() -- Starts the thread.
  • Halt() -- Halts the thread.
  • Play() -- causes the internal Timer to start emitting ticks based on the song tempo and time signature.
  • Pulse() -- listenable method, called when the Timer ticks.

References

  • SongInfo
  • Score

Parser

  • Moves through the Score, and processes notes from the Score as FluidSynth signals.
  • Its position is updated on each CoreDriver Pulse.
  • If there is a note to play on a given pulse, send a signal to FluidSynth.
  • Controlled by Metronome Pulse().

Interface

  • OnPulse() -- Listens for a Pulse event, and plays any notes which fall within that pulse.

References

  • Score
  • Metronome

Conductor

  • Cues Musicians from the Ensemble to add their parts to the score.
  • Controlled by Metronome PulseEvent.
  • Adds and removes musicians from the ensemble.

Interface

  • OnPulse() -- Listens for a Pulse event, and cues musicians to compose for a specified duration.
  • AddMusician() -- adds a new Musician to the Ensemble.
  • RemoveMusician() -- removes a Musician from the Ensemble.

References

  • Score

SongInfo

  • Contains tempo, key signature, time signature which are currently valid.
  • The interface writes modifications to the song here, which are applied when a new measure is loaded by CoreDriver.

Interface

  • UpdateKeySignature() -- changes the key signature, and whether the key is major/minor.
  • UpdateTimeSignature() -- changes the time signature.

References

  • None

MusicianDirectory

  • Contains Musician class references and descriptions.
  • Used to filter Musicians based on tags (genre, instrument, category) to support GUI.

Interface

  • Filter(tags) -- given a set of tags, returns a list of musicians which contain all of those tags.

InstrumentDirectory

  • Contains family hierarchy and filterable list of instruments.

Interface

  • GetParent(instrument) -- given an instrument, returns the parent of that instrument in a familial sense.

    For example, a djembe's parent is a hand drum, a hand drum's parent is a drum, a drum's parent is percussion instrument, ...and so on.

Ensemble

  • A list of musicians. Contains no other data at this time.

Interface

  • Get()
  • Add()
  • Remove()

References

  • Musician

Musician

  • Has a list of modifiable properties such as 'Energy' or 'Bowed.'
  • Has an instrument which is a key in the InstrumentDirectory. This key is written into the score. Used also so the Parser can look up which SoundFont to use.

Interface

  • SetProperty(key, value) -- changes a Musician parameter such as Energy or Complexity.
  • Compose(duration) -- instructs the Musician to add its performance to the score. Duration specifies at least how far into the future the Musician should compose (ie one full beat)

References

  • Instrument
  • InstrumentDirectory

Instrument

  • Simply a key for lookup in InstrumentDirectory()

Interface

  • None

References

  • None

Score

  • Contains Staffs, which contain Measures. Staffs is rarely accessed by anything, just used to add or remove a Musician.
  • Contains ScoreSlices.

Interface

  • GetStaff(Musician) -- returns the staff belonging to a specific Musician.
  • GetScoreSlices() -- gets the head of the ScoreSlice linked list.

References

  • Staff
  • ScoreSlice

Staff

  • Contains Measures.
  • Not intended to be used by any components except for Score.

Interface

  • GetMeasures() -- returns the head of a linked list of Measure.

References

  • Measure

ScoreSlice

  • Represents a vertical slice of a piece of sheet music.
  • Stores a key signature and a time signature, read from SongInfo.
  • Contains Measures indexable by Musician.

Interface

  • GetMeasures() -- a list of measures which are played simultaneously.
  • Next() -- the next StaffMeasure, moving forward in time.
  • Previous() -- the previous StaffMeasure, moving backward in time.

References

  • Measure
  • Musician
  • SongInfo

Measure

  • Has next() and previous() methods to move forward or backward in Score.
  • Contains Notes, implemented as a doubly linked list.

Interface

  • Next() -- return the measure after this one in the Score.
  • Previous() -- return the measure before this one in the Score.
  • GetNotes() -- get the Notes which are in this measure.
  • AppendNote(Note) -- adds a Note to the end of this Measure's Notes.

References

  • Note

Note

  • A note represents a tone and its rhythmic description in the Score.

Interface

  • SetDynamics() -- how hard the note is struck.
  • SetDuration() -- the musical description of the Note's rhythmic value.
  • SetTone(tone, octave) -- describes the Note frequency.
  • SetSlur(slur, type) -- whether or not this note blends into the next note, and how to shift the pitch.
  • Previous() -- get the previous note(s)
  • Next() -- get the next note(s)

References

  • None

Sequence Diagrams

  • NOTE: User is always operating because the user is external to the system, modules of Robot Rock execute one at a time.
  • NOTE: All modules exist permanently, they get created on program statup and destroyed on program exit.

Two User Interaction Use Cases

  • The use cases of opening the Add Instrument box and Filtering the results therein.

User adding (by dragging) an instrument to the canvas

  • The user selects and musician/instrument from the Add Instrument box and drags it onto the canvas, the system automatically begins to play.
  • NOTE: This Use Case assumes the user has opened the Add Instrument box and has Filtered as needed.

Internal Metronome triggering

  • This is an automatic process as long as the system is generating music (that is, the system is in play mode and not paused or stopped).
  • The metronome triggers at a uniform rate dependant on the prescribed tempo of the music.

Class Diagram

High Level Consumer Diagram

  • High Level Consumer Diagram; shows the general layout of the system containing the high level modules relevant to the consumer.

Data Stores

The InstrumentDirectory is a tree classification of instruments based on their genus. This is designed to allow Musicians to find out what an instrument they have never seen before is most related to. The instruments are simply represented as strings in a tree, and are specified as a list of (instrument, parent) tuples in a flat file.

The MusicianDirectory is a filterable list of Musicians. There is a flat file with lists of (MusicianClassPath, tag1, tag2,...) . When RobotRock loads, we build a reverse index mapping each tag to the Musician class. Then, when the user wants to add a new Musician to the Ensemble, the link to instantiate it is available after selecting it from a list that shares common tags.

We do not have any persistent data stores. The Score is a living document representing sheet music for a song that is composed in real time. Using the Score, it would be possibly to generate sheet music.

Alternative Designs

We envisioned a parser which would respond to different pulse events. It was nixed due to the complexity of maintaining multiple pointers in the score.

We also imagined a model where a very tight loop was controlled by a single class, but we removed this because it tightly coupled together too many classes which were conceptually unrelated.

Assumptions

Coding Style Guidelines

Python Zen is our core coding style guideline.

Risk Assesment

Risk Analysis

Summary

The three major concerns from our requirements document (performance, music quality, and usability) are still present as risks in our design spec. Much of the design has been oriented around preventing and mitigating these risks, such as the development of the Score as a large data structure that will contain all the music that has been written by the musicians, and which will be parsed by the parser and passed onto the audio synthesizer. Two new risks that have emerged during the design phase are Synchronization and Packaging. Synchronization deals with making sure that the musicians and parser behave appropriately in relation to each other, and both keep up with each and the beat of the song. Packaging is a risk primarily because none of the members of our group has experience packaging and releasing applications or installers for applications, so it is important that the team begins thinking about packaging early and is not surprised by any complications at the deadline.

Risk: Performance/Responsiveness

  • Chance of occurring: Medium
  • Impact if it occurs Medium
  • Steps taking to increase chance it won't occur: The setup of the musician and score design should enable users to make changes that affect the music in real time. The score will be set up such that a measure can be overwritten before it gets passed off to the parser if some instrument settings are changed.
  • Mitigation plan should it occur: The ideal scenario is that the musicians and parser will be separated by a very small number of beats. This number of beats that separates the two can always be modified, and if there is some delay between the user changing an option and that being reflected in the audio output, it should not be a show stopper.

Risk: Music Quality

  • Chance of occurring: Medium
  • Impact if it occurs: High
  • Steps taking to increase chance it won't occur: Created a Score that all musicians will be able to refer to what other musicians played previously, and what is currently being played for the musicians that decided before it. This design should allow musicians to easily gather data about what others are playing to assist its own decisions. This should allow us to maintain the slight delay between musicians and parser and still give real time feedback.
  • Mitigation plan should it occur: The most probable cause of risk here is that the musicians computations are unable to keep up with the speed of the song, and the musicians will be most susceptible to this in high tempo, high energy situations where the computations will be complex and have a short period of time to run. If this does not occur frequently, a musician can just be passed (play nothing) if it does not meet the time requirement and the song will go on, but if the problem is consistent, then the maximum tempo may need to be reduced, and more resources dedicated to the efficiency of AI algorithms.

Risk: Synchronization

  • Chance of occurring: Low
  • Impact if it occurs: High
  • Steps taking to increase chance it won't occur: Creating a Metronome class that will control the timing of both the ensemble (Conductor class) and Audio Synthesis (Parser class). The ensemble will always be a fixed number of ticks ahead of the parser.
  • Mitigation plan should it occur: If the either section is falling behind,a few options exist. If they only fall behind on rare occasions, the delay between the two can be increased to allow for those extreme cases to be handled. If it is a consistent problem (particularly at high tempos), the maximum tempo may need to be limited because that is when the largest strain will be placed on the musician and audio synthesis system.

Risk: Usability

  • Chance of occurring: Medium
  • Impact if it occurs: High
  • Steps taking to increase chance it won't occur: User tests are great here. Whenever a new UI feature is developed, the developers will take a couple minutes to check it out. Asking others in the work area to sit down with it for a couple minutes will also ensure that development resources are not wasted implementing features that people do not want or understand. A tutorial will also be developed to teach new users the basics of how to get started.
  • Mitigation plan should it occur: Should the test users have significant difficulty understanding, dedicate more development resources to modifying the tutorial in order to be clearer and more concise. If features need to be removed/hidden to reduce complexity, focus on removing buttons/features that are causing confusion, and that few users use.

Risk: Packaging

  • Chance of occurring: Low
  • Impact if it occurs: Low
  • Steps taking to increase chance it won't occur: Assigned a team member (Travis) to be responsible for considering installation early and often. This should prevent the packaging process form becoming a major headache down the road. Our goal is to be able to provide a Windows installer, as well as the required Linux installer, because we would like the application to be usable by the large majority of users.
  • Mitigation plan should it occur: We may have to put off the Windows installer in the event that it is much more complicated than we anticipate, at least until after the project due date.

Project Schedule

Milestones

Zero Feature Release (Due Date: 4/26)

Tasks:

  • Code to Pop Up Window (Assigned to Tim) : Our first release, which will feature a window with some useless buttons.
  • Set up Automatic Test Scaffolding (Assigned to Michael) : Create necessary scripts that will enable one step checkout, build, and test execution for our project.
  • Create a Windows installer (Assigned to Travis) : Create the first basic installer for our application, so we know how the process goes.

Stubs/Skeleton Complete (Due Date: 5/1)

Tasks:

  • Finish Unit Tests for all Modules (Assigned to all members) : Should have unit tests ready to be run by the testing protocol (depends on testing protocol to be finished).
  • Finish Stubs (Assigned to all members) : Have modules fleshed out with stubs, so that other modules may call them.
  • Interface for UI Controller (Assigned to Michael) : Have the interface ready for the UI Controller, so that it is clear how it will handle events from the GUI and pass information to the musicians and core module
  • Interface for Instrument Tree (Assigned to Alan) : Describe how the hierarchy of instruments will work, so musicians can learn about new instruments.
  • UI Skeleton Complete (Assigned to Tim) : Have the simple widgets completed and laid out (list of simple widgets has been compiled). Callbacks do not have to be hooked up at this point.

Features (except Musicians) complete (Due Date: 5/6)

Use cases should be able to work at this point, the first instrument (metronome) will be ready, and general music parameters should be adjustable with proper effects.

Tasks:

  • Unit tests should pass (Assigned to all) : Modules need not be hooked up to each other at this point (depends on unit tests being written).
  • First musician complete (Assigned to Rich) : Metronome (holds beat, tempo)
  • UI is functional (Assigned to Tim) : UI callbacks are hooked up (depends on UI skeleton, UI controller being complete)
  • Parser/Synthesizer handles simple beats (Assigned to Travis) : The parser can handle whole,half,quarter notes for the metronome, and synthesize the sound.
  • Music controls functional : Can adjust tempo, time signature, and key signature successfully.
  • System Integration Tests Written (Assigned to all) : System tests should be completed so modules are ready to be hooked up and tested.

Beta Release (Due Date: 5/13)

Tasks:

  • System Integration Tests Pass : Modules are hooked up and their tests are passing
  • Drummer/Bass/Synth Musicians Implemented (Assigned to Rich) : Basic set of musicians is complete
  • Second Iteration of UI complete (Assigned to Tim) : Previous UI user tested, feedback implemented
  • Parser/Synthesizer complete (Assigned to Travis) : Parser can handle our most complicated beats and rhythms (TBD) and synthesize
  • Tutorial for UI complete (Assigned to Michael / Tim) : Tutorial written to show users how to get started.
  • Create windows/linux installer (Assigned to Travis) : Installers to be used for beta testing
  • Song export feature implemented : Users can now export their performances into a standard audio file format

Final Release (Due Date: 5/29)

Tasks:

  • Implement user feedback from testing beta version (Assigned to all)
  • Implement a couple more musicians (Assigned to Rich)
  • Create the final installer (Assigned to Travis)

Team Structure

  • Project Manager: Alan is assigned this role, as he developed the initial vision and project goals. His responsibilities are to keep the team on track and oversee the project's technical development.
  • UI/Documentation Lead: Tim gets this role for his interest in designing simple and intuitive interfaces. His responsibilities are to deliver a polished, highly usable UI.
  • Audio Lead: Travis' detailed knowledge of MIDI and FluidSynth earn him the title of Audio Lead. His role is to ensure the audio output pipeline is responsive and produces high-quality tones.
  • Test Lead/SDE: Mike doubles as the owner of the test plan, and a developer focusing on UI but assisting on all components on development. He is a free agent who will focus his efforts on whichever component needs the most help. His test ownership role doesn't mean he writes all the tests--he simply oversees the test process.
  • AI Lead -- Rich is focused full time on making the AI Musicians robust, polished and sophisticated.

Test Plan

Unit Test Strategy:

  • These tests will cover the functions in each class, with a set of tests corresponding to each function.
  • Each developer will be responsible for creating their own unit tests for their own modules.
    Each developer must first create a paper test plan (due 4/28), which will be reviewed by the other developers. After reviewing and editing, the unit tests will be coded (due 5/1). At this point, all unit tests will fail.
  • Unit tests should be run every time before code is committed. Developers must run the unit tests for their own modules, as well as any other modules they may have edited.

System Test Strategy:

  • These tests will cover interactions between different modules, with a set of tests for every interaction (function calls, etc.)
  • Each developer will be responsible for creating tests for any interactions in which their module calls upon functionality of another module.These tests should be written as prototypes, and then reviewed by the developers for both modules, and finally coded up. All integration tests should pass by the point of beta release (estimated 5/13).
  • System tests should be run every time code is committed. Tests should be run for all interactions involving modules that have been modified.

Usability Test Strategy:

  • These tests will cover the user experience aspects of the application, designed to determine what areas in our application cause confusion or an excessive amount of work for our users.
  • Usability tests will be developed as a group and should be developed before user studies and beta release. Tests should be designed as a set of tasks for a user to do that cover all the primary functionality of the application.
  • Usability tests will be run through user studies, which should occur at the time of beta release, and at the time before final release. Developers should also try to complete the usability tests to serve as a good gauge for the usability in between studies.

Bug Tracking: The ticketing feature in the project workspace on Assembla will be used to report bugs, assign them to team members, and report the resolution of bugs.

Documentation Plan

The program will come with a set of static html pages and images, viewable by the user's favorite browser or html viewer.

Specifically, these help pages would include:

  • A "Getting Started" guide which walks the user through the process of adding new instruments, changing instrument and song settings, deleting instruments, and saving/loading a song. All instructions here include screenshots.

  • Explanation of what the software does (not internally, but from a user perspective)

  • Breakdown of GUI components, describing exactly what everything does (again from a user perspective)

  • FAQ

  • Detail pages on each instrument, describing that instrument and how it responds to other instruments

  • Developer pages describing the process of writing a new instrument compatible with the software, as well as the installation process of new instruments.

  • Index for quick lookup of terms

These help pages will be accessible either by navigating to them on disk, or by selecting to view them via the program's help menu. If the program were to be distributed from a website, then that site would also host a copy of the most recent documentation (viewable online).

In addition, all User Interface elements of sufficient complexity will have tooltips quickly explaining their function.

Finally, if time allows, the program itself will have an interactive getting started function that will be an option when the program is first run. This interactive guide will take the user step by step through the same actions described in the html document. For example, when the time comes for the user to add an instrument, a large arrow will appear on screen and point to the add instrument button, along with a text box asking the user to "Click on the 'Add instrument' button to add a new instrument to the stage"