001/*
002 *  Software License Agreement
003 *
004 * Copyright (C) Cross The Road Electronics.  All rights
005 * reserved.
006 * 
007 * Cross The Road Electronics (CTRE) licenses to you the right to 
008 * use, publish, and distribute copies of CRF (Cross The Road) firmware files (*.crf) and Software
009 * API Libraries ONLY when in use with Cross The Road Electronics hardware products.
010 * 
011 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
012 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
013 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
014 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
015 * CROSS THE ROAD ELECTRONICS BE LIABLE FOR ANY INCIDENTAL, SPECIAL, 
016 * INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
017 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
018 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
019 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
020 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
021 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE
022 */
023package com.ctre.phoenix.music;
024
025import com.ctre.phoenix.ErrorCode;
026import com.ctre.phoenix.motorcontrol.can.TalonFX;
027import java.util.Collection;
028
029/**
030 * An Orchestra is used to play music through Talon FX motor controllers.
031 * It uses a "Chirp" (.chrp) music file that can be generated using Phoenix Tuner.
032 * 
033 * Chirp files are generated from standard MIDI files.
034 * Each Talon FX can only play a single track within the music file.
035 * For multi-track files, multiple Talon FXs are needed.
036 *  ie, The first track will be played through the first Talon FX added,
037 *  the second track will be played through the second Talon FX added, etc.
038 * 
039 * Any Chirp file located in the src/main/deploy directory of your FRC project 
040 *  will automatically be copied to the roboRIO on code deploy.
041 * 
042 * To use the Orchestra:
043 *  - Add the Talon FXs to be used as instruments
044 *  - Load the Chirp file to be played using the loadMusic routine.
045 * Both of these can also be done in the Orchestra constructor.
046 * 
047 * Once ready, the Orchestra can be controlled using standard
048 * play/pause/stop routines.
049 * 
050 * New music files can be loaded at any time.
051 * 
052 * The robot must be enabled to play music.
053 * 
054 * Calling set on any of the TalonFX instruments while the orchestra is
055 * playing will pause the orchestra.
056 */
057public class Orchestra {
058    private long m_handle;
059
060    /**
061     * Constructor for an Orchestra Object.
062     * Call AddInstrument after this to add the instruments.
063     */
064    public Orchestra() {
065        m_handle = OrchestraJNI.JNI_new_Orchestra();
066    }
067    /**
068     * Constructor for an Orchestra Object.
069     * @param instruments
070     *          A collection of TalonFX's that will be used as instruments
071     *          inside the orchestra.
072     */
073    public Orchestra(Collection<TalonFX> instruments) {
074        this();
075
076        for(TalonFX instrument : instruments) {
077            addInstrument(instrument);
078        }
079    }
080    /**
081     * Constructor for an Orchestra Object
082     * @param instruments
083     *          A collection of TalonFX's that will be used as instruments
084     *          inside the orchestra.
085     * @param filePath
086     *          The path to the music file to immediately load into
087     *          the orchestra.
088     */
089    public Orchestra(Collection<TalonFX> instruments, String filePath) {
090        this(instruments);
091
092        loadMusic(filePath);
093    }
094
095    /**
096     * Loads a Chirp file at the specified file path.
097     * 
098     * If the Chirp file is inside your "src/main/deploy" directory
099     * this file will be automatically deployed to a default directory in
100     * the RoboRIO when you deploy code. For these files, the name and file 
101     * extension is sufficient.
102     * 
103     * Use Tuner to create a Chirp file.
104     * @param filePath
105     *              The path to the Chirp File.
106     * @return Error Code generated by function. 0 indicates no error. 
107     */
108    public ErrorCode loadMusic(String filePath) {
109        int retval = OrchestraJNI.JNI_LoadMusic(m_handle, filePath);
110        return ErrorCode.valueOf(retval);
111    }
112
113    /**
114     * Plays the music file that's loaded. 
115     * If the player is paused, this will resume.
116     * This will also resume a song if the orchestra was interrupted.
117     * @return Error Code generated by function. 0 indicates no error. 
118     */
119    public ErrorCode play() {
120        int retval = OrchestraJNI.JNI_Play(m_handle);
121        return ErrorCode.valueOf(retval);
122    }
123
124    /**
125     * Stops the music file that's loaded. 
126     * This resets the current position in the track to the start.
127     * @return Error Code generated by function. 0 indicates no error. 
128     */
129    public ErrorCode stop() {
130        int retval = OrchestraJNI.JNI_Stop(m_handle);
131        return ErrorCode.valueOf(retval);
132    }
133
134    /**
135     * Pauses the music file that's loaded. 
136     * This saves the current position in the track, so it can be resumed later.
137     * Pausing while stopped is an invalid request.
138     * @return Error Code generated by function. 0 indicates no error. 
139     */
140    public ErrorCode pause() {
141        int retval = OrchestraJNI.JNI_Pause(m_handle);
142        return ErrorCode.valueOf(retval);
143    }
144
145    /**
146     * Returns whether the current track is actively playing or not
147     * @return True if playing, false otherwise 
148     */
149    public boolean isPlaying() {
150        return OrchestraJNI.JNI_IsPlaying(m_handle);
151    }
152    
153    /**
154     * @return The current timestamp of the music file (playing or paused) in milliseconds.
155     * The timestamp will reset to zero whenever loadMusic() or stop() is called.
156     * If isPlaying() returns false, this routine can be used to determine if music is stopped or paused.
157     */
158    public int getCurrentTime() {
159        return OrchestraJNI.JNI_GetCurrentTime(m_handle);
160    }
161
162    /**
163     * Clears all instruments in the orchestra.
164     * @return Error Code generated by function. 0 indicates no error. 
165     */
166    public ErrorCode clearInstruments() {
167        int retval = OrchestraJNI.JNI_ClearInstruments(m_handle);
168        return ErrorCode.valueOf(retval);
169    }
170
171    /**
172     * Adds another instrument to the orchestra.
173     * @param instrument
174     *              TalonFX to add to orchestra
175     * @return Error Code generated by function. 0 indicates no error. 
176     */
177    public ErrorCode addInstrument(TalonFX instrument) {
178        int retval = OrchestraJNI.JNI_AddInstrument(m_handle, instrument.getHandle());
179        return ErrorCode.valueOf(retval);
180    }
181}