diff options
-rw-r--r-- | Edit/MainWindow.py | 26 | ||||
-rw-r--r-- | Edit/TrackInterface.py | 118 | ||||
-rwxr-xr-x | Resources/Images/brush.png | bin | 0 -> 3544 bytes | |||
-rwxr-xr-x | Resources/Images/brushDown.png | bin | 0 -> 4462 bytes | |||
-rwxr-xr-x | Resources/Images/krecord.png | bin | 0 -> 1911 bytes | |||
-rwxr-xr-x | Resources/Images/krecordDown.png | bin | 0 -> 1814 bytes | |||
-rwxr-xr-x | Resources/Images/krecordOver.png | bin | 0 -> 1878 bytes | |||
-rw-r--r-- | Resources/Images/record2.png | bin | 1650 -> 2248 bytes | |||
-rwxr-xr-x | Resources/Images/record2Down.png | bin | 0 -> 2087 bytes | |||
-rwxr-xr-x | Resources/Images/record2Over.png | bin | 0 -> 2166 bytes | |||
-rwxr-xr-x | TamTam.py | 12 | ||||
-rw-r--r-- | Util/Clooper/Makefile | 2 | ||||
-rw-r--r-- | Util/Clooper/aclient.cpp | 314 | ||||
-rw-r--r-- | Util/Clooper/audio.cpp | 681 | ||||
-rw-r--r-- | Util/Clooper/log.cpp | 47 | ||||
-rw-r--r-- | Util/KeyboardWindow.py | 155 | ||||
-rw-r--r-- | Util/Trackpad.py | 2 | ||||
-rw-r--r-- | Welcome.py | 10 |
18 files changed, 1097 insertions, 270 deletions
diff --git a/Edit/MainWindow.py b/Edit/MainWindow.py index 5fce403..e6d7118 100644 --- a/Edit/MainWindow.py +++ b/Edit/MainWindow.py @@ -256,7 +256,7 @@ class MainWindow( SubActivity ): #self.GUI["2XYSliderYAdjustment"] = gtk.Adjustment( 650, 500, 1000, 1, 1, 1 ) #self.GUI["2XYSlider"] = XYSlider( self.GUI["2XYSliderFixed"], self.GUI["2XYSliderButton"], self.GUI["2XYSliderXAdjustment"], self.GUI["2XYSliderYAdjustment"], True, True ) #self.GUI["2rightPanel"].pack_start( self.GUI["2XYSlider"], False, False, 0 ) - self.trackInterface = TrackInterface( self.noteDB, self ) + self.trackInterface = TrackInterface( self.noteDB, self, self.getScale ) self.noteDB.addListener( self.trackInterface, TrackInterfaceParasite, True ) self.trackInterface.set_size_request( -1, 713 ) self.GUI["2rightPanel"].pack_start( self.trackInterface, False, False, 0 ) @@ -266,17 +266,21 @@ class MainWindow( SubActivity ): self.GUI["2toolPanel"].set_size_request( -1, toolPanelHeight ) # + + tool box self.GUI["2toolBox"] = formatRoundBox( RoundHBox(), Config.BG_COLOR ) - self.GUI["2toolBox"].set_size_request( 144, -1 ) + self.GUI["2toolBox"].set_size_request( 204, -1 ) self.GUI["2toolPointerButton"] = ImageRadioButton( None, Config.IMAGE_ROOT+"pointer.png", Config.IMAGE_ROOT+"pointerDown.png", backgroundFill = Config.BG_COLOR ) self.GUI["2toolPointerButton"].connect( "clicked", self.handleToolClick , "default" ) self.GUI["2toolBox"].pack_start( self.GUI["2toolPointerButton"] ) self.GUI["2toolPencilButton"] = ImageRadioButton( self.GUI["2toolPointerButton"], Config.IMAGE_ROOT+"pencil.png", Config.IMAGE_ROOT+"pencilDown.png", backgroundFill = Config.BG_COLOR ) self.GUI["2toolPencilButton"].connect( "clicked", self.handleToolClick , "draw" ) self.GUI["2toolBox"].pack_start( self.GUI["2toolPencilButton"] ) + self.GUI["2toolPencilButton"] = ImageRadioButton( self.GUI["2toolPointerButton"], Config.IMAGE_ROOT+"brush.png", Config.IMAGE_ROOT+"brushDown.png", backgroundFill = Config.BG_COLOR ) + self.GUI["2toolPencilButton"].connect( "clicked", self.handleToolClick , "paint" ) + self.GUI["2toolBox"].pack_start( self.GUI["2toolPencilButton"] ) + self.GUI["2toolPanel"].pack_start( self.GUI["2toolBox"], False, False ) self.GUI["2rightPanel"].pack_start( self.GUI["2toolPanel"], False ) # + + context box (for context sensitive buttons, nothing to do with CAIRO) - contextWidth = 674 + contextWidth = 594 self.GUI["2contextBox"] = formatRoundBox( RoundFixed(), Config.BG_COLOR ) self.GUI["2contextBox"].set_size_request( contextWidth, -1 ) self.GUI["2contextPrevButton"] = ImageButton( Config.IMAGE_ROOT+"arrowEditLeft.png", Config.IMAGE_ROOT+"arrowEditLeftDown.png", Config.IMAGE_ROOT+"arrowEditLeftOver.png", backgroundFill = Config.BG_COLOR ) @@ -338,9 +342,9 @@ class MainWindow( SubActivity ): self.GUI["2toolPanel"].pack_start( self.GUI["2contextBox"], False ) # + + transport box self.GUI["2transportBox"] = formatRoundBox( RoundHBox(), Config.BG_COLOR ) - self.GUI["2keyRecordButton"] = ImageToggleButton( Config.IMAGE_ROOT+"record2.png", Config.IMAGE_ROOT+"record2sel.png", Config.IMAGE_ROOT+"record2sel.png", backgroundFill = Config.BG_COLOR ) + self.GUI["2keyRecordButton"] = ImageToggleButton( Config.IMAGE_ROOT+"krecord.png", Config.IMAGE_ROOT+"krecordDown.png", Config.IMAGE_ROOT+"krecordOver.png", backgroundFill = Config.BG_COLOR ) self.GUI["2keyRecordButton"].connect("clicked", self.handleKeyboardRecordButton ) - self.GUI["2recordButton"] = ImageToggleButton( Config.IMAGE_ROOT+"record.png", Config.IMAGE_ROOT+"recordsel.png", Config.IMAGE_ROOT+"recordsel.png", backgroundFill = Config.BG_COLOR ) + self.GUI["2recordButton"] = ImageToggleButton( Config.IMAGE_ROOT+"record2.png", Config.IMAGE_ROOT+"record2Down.png", Config.IMAGE_ROOT+"record2Over.png", backgroundFill = Config.BG_COLOR ) self.GUI["2recordButton"].connect("clicked", self.handleAudioRecord ) self.GUI["2transportBox"].pack_start( self.GUI["2keyRecordButton"] ) self.GUI["2transportBox"].pack_start( self.GUI["2recordButton"] ) @@ -831,6 +835,9 @@ class MainWindow( SubActivity ): #else: # recordButton.hide() + def getScale(self): + return self.generationPanel.scale + def handleVolume( self, widget ): self._data["volume"] = round( widget.get_value() ) self.csnd.setMasterVolume(self._data["volume"]) @@ -1648,7 +1655,8 @@ class MainWindow( SubActivity ): return self.noteDB.updateNote( n.page, n.track, n.id, PARAMETER.DURATION, adjustedDuration) if onsetQuantized >= n.cs.onset and (onsetQuantized+2) <= (n.cs.onset + n.cs.duration): - return + self.noteDB.deleteNote(n.page, n.track, n.id) + #return csnote = CSoundNote(onset = 0, pitch = pitch, @@ -1709,7 +1717,8 @@ class MainWindow( SubActivity ): for n in self.noteDB.getNotesByTrack( csId[0], csId[1] ): if csId[3] < n.cs.onset and (csId[3] + newDuration) >= n.cs.onset: - newDuration = n.cs.onset - csId[3] + self.noteDB.deleteNote(n.page, n.track, n.id) + #newDuration = n.cs.onset - csId[3] break self.noteDB.updateNote( csId[0], csId[1], csId[2], PARAMETER.DURATION, newDuration) @@ -1727,7 +1736,8 @@ class MainWindow( SubActivity ): for n in self.noteDB.getNotesByTrack( self.csId[0], self.csId[1] ): if self.csId[3] < n.cs.onset and (self.csId[3] + newDuration) > n.cs.onset: - newDuration = n.cs.onset - self.csId[3] + self.noteDB.deleteNote(n.page, n.track, n.id) + #newDuration = n.cs.onset - self.csId[3] break self.noteDB.updateNote( self.csId[0], self.csId[1], self.csId[2], PARAMETER.DURATION, newDuration) diff --git a/Edit/TrackInterface.py b/Edit/TrackInterface.py index f517b1d..5b4780e 100644 --- a/Edit/TrackInterface.py +++ b/Edit/TrackInterface.py @@ -14,7 +14,7 @@ from Edit.MainWindow import CONTEXT from Util.NoteDB import PARAMETER from Util.CSoundNote import CSoundNote - +from Generation.GenerationConstants import GenerationConstants from Util.Profiler import TP class SELECTNOTES: @@ -30,6 +30,7 @@ class INTERFACEMODE: DRAW = 1 PASTE_NOTES = 2 PASTE_TRACKS = 3 + PAINT = 4 class TrackInterfaceParasite: def __init__( self, noteDB, owner, note ): @@ -43,11 +44,12 @@ class TrackInterfaceParasite: class TrackInterface( gtk.EventBox ): - def __init__( self, noteDB, owner ): + def __init__( self, noteDB, owner, getScaleFunction ): gtk.EventBox.__init__( self ) self.noteDB = noteDB self.owner = owner + self.getScale = getScaleFunction self.drawingArea = gtk.DrawingArea() self.drawingAreaDirty = False # are we waiting to draw? @@ -62,6 +64,7 @@ class TrackInterface( gtk.EventBox ): self.curPage = -1 # this isn't a real page at all! self.curBeats = 4 + self.painting = False self.selectedNotes = [ [] for i in range(Config.NUMBER_OF_TRACKS) ] @@ -316,6 +319,8 @@ class TrackInterface( gtk.EventBox ): if mode == "draw": self.interfaceMode = INTERFACEMODE.DRAW + elif mode == "paint": + self.interfaceMode = INTERFACEMODE.PAINT elif mode == "paste_notes": self.interfaceMode = INTERFACEMODE.PASTE_NOTES self.setCurrentAction("paste", self) @@ -423,6 +428,59 @@ class TrackInterface( gtk.EventBox ): TP.ProfileEnd( "TI::handleButtonPress" ) return + elif self.interfaceMode == INTERFACEMODE.PAINT: + self.scale = self.getScale() + self.painting = True + self.paintTrack = i + self.GRID = 3. + if i == self.drumIndex: + pitch = min( self.pixelsToPitchDrumFloor( self.clickLoc[1] - self.trackLimits[i][1] + Config.HIT_HEIGHT//2 )//Config.PITCH_STEP_DRUM, Config.NUMBER_OF_POSSIBLE_PITCHES_DRUM-1)*Config.PITCH_STEP_DRUM + Config.MINIMUM_PITCH_DRUM + if pitch < 24: + pitch = 24 + elif pitch > 48: + pitch = 48 + else: + pitch = pitch + else: + pitch = min( self.pixelsToPitchFloor( self.clickLoc[1] - self.trackLimits[i][1] + Config.NOTE_HEIGHT//2 ), Config.NUMBER_OF_POSSIBLE_PITCHES-1) + Config.MINIMUM_PITCH + if pitch < 24: + pitch = 24 + elif pitch > 48: + pitch = 48 + else: + pitch = pitch + + minDiff = 100 + for pit in GenerationConstants.SCALES[self.scale]: + diff = abs(pitch-(pit+36)) + if diff < minDiff: + minDiff = diff + nearestPit = pit + pitch = nearestPit+36 + + onset = self.pixelsToTicksFloor( self.curBeats, self.clickLoc[0] - self.trackRect[i].x ) + onset = self.GRID * int(onset / self.GRID + 0.5) + self.pLastPos = onset + if i != self.drumIndex: + noteS = self.noteDB.getNotesByTrack(self.curPage, i) + for n in noteS: + if onset >= n.cs.onset and onset < (n.cs.onset + n.cs.duration): + self.noteDB.deleteNote(self.curPage, i, n.id) + + cs = CSoundNote( onset, + pitch, + 0.75, + 0.5, + 1, + i, + instrumentId = self.owner.getTrackInstrument(i).instrumentId ) + cs.pageId = self.curPage + id = self.noteDB.addNote( -1, self.curPage, i, cs ) + self.noteDB.updateNote(self.curPage, i, id, PARAMETER.DURATION, self.GRID) + n = self.noteDB.getNote( self.curPage, i, id, self ) + self.selectNotes( { i:[n] }, True ) + n.playSampleNote( False ) + self.curAction = True TP.ProfileEnd( "TI::handleButtonPress" ) @@ -430,6 +488,7 @@ class TrackInterface( gtk.EventBox ): def handleButtonRelease( self, widget, event ): if not self.clickButton: return # we recieved this event but were never clicked! (probably a popup window was open) self.clickButton = 0 + self.painting = False TP.ProfileBegin( "TI::handleButtonRelease" ) @@ -477,6 +536,61 @@ class TrackInterface( gtk.EventBox ): event.y = float(y) event.state = state + if self.painting: + i = self.paintTrack + curPos = self.pixelsToTicksFloor(self.curBeats, event.x - self.trackRect[i].x) + gridPos = self.GRID * int(curPos / self.GRID) + if gridPos >= self.curBeats * Config.TICKS_PER_BEAT: + return + if gridPos != self.pLastPos: + self.pLastPos = gridPos + if i == self.drumIndex: + pitch = min( self.pixelsToPitchDrumFloor( int(event.y) - self.trackLimits[i][1] + Config.HIT_HEIGHT//2 )//Config.PITCH_STEP_DRUM, Config.NUMBER_OF_POSSIBLE_PITCHES_DRUM-1)*Config.PITCH_STEP_DRUM + Config.MINIMUM_PITCH_DRUM + if pitch < 24: + pitch = 24 + elif pitch > 48: + pitch = 48 + else: + pitch = pitch + else: + pitch = min( self.pixelsToPitchFloor( int(event.y) - self.trackLimits[i][1] + Config.NOTE_HEIGHT//2 ), Config.NUMBER_OF_POSSIBLE_PITCHES-1) + Config.MINIMUM_PITCH + if pitch < 24: + pitch = 24 + elif pitch > 48: + pitch = 48 + else: + pitch = pitch + minDiff = 100 + for pit in GenerationConstants.SCALES[self.scale]: + diff = abs(pitch-(pit+36)) + if diff < minDiff: + minDiff = diff + nearestPit = pit + pitch = nearestPit+36 + + onset = gridPos + if i != self.drumIndex: + noteS = self.noteDB.getNotesByTrack(self.curPage, i) + for n in noteS: + if onset >= n.cs.onset and onset < (n.cs.onset + n.cs.duration): + self.noteDB.deleteNote(self.curPage, i, n.id) + + cs = CSoundNote( onset, + pitch, + 0.75, + 0.5, + 1, + i, + instrumentId = self.owner.getTrackInstrument(i).instrumentId ) + cs.pageId = self.curPage + id = self.noteDB.addNote( -1, self.curPage, i, cs ) + self.noteDB.updateNote(self.curPage, i, id, PARAMETER.DURATION, self.GRID) + n = self.noteDB.getNote( self.curPage, i, id, self ) + self.selectNotes( { i:[n] }, True ) + n.playSampleNote( False ) + self.curAction = True + + TP.ProfileEnd( "TI::handleMotion::Common" ) if not self.clickButton and self.curAction != "paste": # we recieved this event but were never clicked! (probably a popup window was open) diff --git a/Resources/Images/brush.png b/Resources/Images/brush.png Binary files differnew file mode 100755 index 0000000..60d29a9 --- /dev/null +++ b/Resources/Images/brush.png diff --git a/Resources/Images/brushDown.png b/Resources/Images/brushDown.png Binary files differnew file mode 100755 index 0000000..ea46632 --- /dev/null +++ b/Resources/Images/brushDown.png diff --git a/Resources/Images/krecord.png b/Resources/Images/krecord.png Binary files differnew file mode 100755 index 0000000..ee40bc1 --- /dev/null +++ b/Resources/Images/krecord.png diff --git a/Resources/Images/krecordDown.png b/Resources/Images/krecordDown.png Binary files differnew file mode 100755 index 0000000..754d3f0 --- /dev/null +++ b/Resources/Images/krecordDown.png diff --git a/Resources/Images/krecordOver.png b/Resources/Images/krecordOver.png Binary files differnew file mode 100755 index 0000000..16e04de --- /dev/null +++ b/Resources/Images/krecordOver.png diff --git a/Resources/Images/record2.png b/Resources/Images/record2.png Binary files differindex f9dd7be..f7bdc4f 100644 --- a/Resources/Images/record2.png +++ b/Resources/Images/record2.png diff --git a/Resources/Images/record2Down.png b/Resources/Images/record2Down.png Binary files differnew file mode 100755 index 0000000..0e7923c --- /dev/null +++ b/Resources/Images/record2Down.png diff --git a/Resources/Images/record2Over.png b/Resources/Images/record2Over.png Binary files differnew file mode 100755 index 0000000..3830034 --- /dev/null +++ b/Resources/Images/record2Over.png @@ -52,7 +52,8 @@ class TamTam(Activity): self.set_resizable(False) self.trackpad = Trackpad( self ) - self.keyboardWindow = KeyboardWindow(8) + self.keyboardWindow = KeyboardWindow(size = 8, popup = True) + self.keyboardWindow.color_piano() self.preloadTimeout = None @@ -62,7 +63,9 @@ class TamTam(Activity): self.connect( "key-press-event", self.onKeyPress ) self.connect( "key-release-event", self.onKeyRelease ) self.connect( "key-press-event", self.keyboardWindow.handle_keypress) - self.connect( "key-release-event", self.keyboardWindow.handle_keyrelease ) + self.connect( "key-release-event", self.keyboardWindow.handle_keyrelease) + self.connect( "button-press-event", self.keyboardWindow.handle_mousePress) + self.connect( "button-release-event", self.keyboardWindow.handle_mouseRelease) self.mode = None self.modeList = {} @@ -167,12 +170,13 @@ class TamTam(Activity): return elif key == 49:#39: S #self.set_mode('synth') - os.spawnlp(os.P_NOWAIT,'/usr/share/activities/TamTam.activity/cnee','/usr/share/activities/TamTam.activity/cnee', '--record', '--keyboard', '--mouse', '--stop-key', 'h', '--out-file', '/home/olpc/test.xnl') + self.keyboardWindow.hide_all() + l = os.spawnlp(os.P_NOWAIT,'/usr/share/activities/TamTam.activity/cnee','/usr/share/activities/TamTam.activity/cnee', '--record', '--keyboard', '--mouse', '--stop-key', 'h', '--out-file', '/home/olpc/test.xnl') return elif key == 10:#25: W #self.set_mode('welcome') self.keyboardWindow.show_all() - os.spawnlp(os.P_NOWAIT,'/usr/share/activities/TamTam.activity/cnee','/usr/share/activities/TamTam.activity/cnee', '--replay', '--keyboard', '--mouse', '--file', '/home/olpc/test.xnl') + l = os.spawnlp(os.P_NOWAIT,'/usr/share/activities/TamTam.activity/cnee','/usr/share/activities/TamTam.activity/cnee', '--replay', '--keyboard', '--mouse', '--file', '/home/olpc/test.xnl') return elif key == 53: #X self.destroy() diff --git a/Util/Clooper/Makefile b/Util/Clooper/Makefile index 3b585f2..a1d1870 100644 --- a/Util/Clooper/Makefile +++ b/Util/Clooper/Makefile @@ -13,7 +13,7 @@ LDFlAGS+=-lpython2.4 all : aclient.so -aclient.so : aclient.cpp +aclient.so : aclient.cpp audio.cpp g++ $(CPPFLAGS) $(CXXFLAGS) -shared -o $@ $< $(LDFLAGS) clean : diff --git a/Util/Clooper/aclient.cpp b/Util/Clooper/aclient.cpp index 0d73c7e..c84fece 100644 --- a/Util/Clooper/aclient.cpp +++ b/Util/Clooper/aclient.cpp @@ -14,13 +14,6 @@ #include <csound/csound.h> #include <alsa/asoundlib.h> -#define ERROR_HERE if (_debug && (VERBOSE > 0)) fprintf(_debug, "ERROR: %s:%i\n", __FILE__, __LINE__) - -#define IF_DEBUG(N) if (_debug && (VERBOSE > N)) - -int VERBOSE = 2; -FILE * _debug = NULL; - static double pytime(const struct timeval * tv) { struct timeval t; @@ -31,6 +24,18 @@ static double pytime(const struct timeval * tv) } return (double) tv->tv_sec + (double) tv->tv_usec / 1000000.0; } +#include "log.cpp" +#include "audio.cpp" + +#define ERROR_HERE if (_debug && (VERBOSE > 0)) fprintf(_debug, "ERROR: %s:%i\n", __FILE__, __LINE__) + +#define IF_DEBUG(N) if (_debug && (VERBOSE > N)) + +#define NEWAUDIO 0 + +int VERBOSE = 3; +FILE * _debug = NULL; + struct ev_t { @@ -116,187 +121,6 @@ struct ev_t csoundScoreEvent(csound, type, ¶m[0], param.size()); } }; -struct SystemStuff -{ - static void setscheduler(void) - { - struct sched_param sched_param; - - if (sched_getparam(0, &sched_param) < 0) { - printf("Scheduler getparam failed...\n"); - return; - } - sched_param.sched_priority = sched_get_priority_max(SCHED_RR); - - if (sched_setscheduler(0, SCHED_RR, &sched_param)) - { - if (_debug && (VERBOSE > 2)) printf("WARNING: Scheduler set to Round Robin with priority %i failed!\n", sched_param.sched_priority); - } - else - { - if (_debug && (VERBOSE > 2)) printf("INFO: Scheduler set to Round Robin with priority %i.\n", sched_param.sched_priority); - } - } - - /** the currently opened pcm hande */ - snd_pcm_t * pcm; - snd_pcm_uframes_t period_size; - unsigned int frame_rate; - - SystemStuff() : pcm(NULL), period_size(0), frame_rate(0) - { - } - ~SystemStuff() - { - if (pcm) close(0); - } - - int open(unsigned int rate0, int upsample_max, snd_pcm_uframes_t period0, unsigned int p_per_buff) - { - snd_pcm_hw_params_t *hw; - - if (pcm) - { - IF_DEBUG(0) fprintf(_debug, "ERROR: open called twice! First close the sound device\n"); - return -1; - } - - if ( 0 > snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0)) { ERROR_HERE; return -1; } - if ( 0 > snd_pcm_hw_params_malloc(&hw)) { ERROR_HERE; snd_pcm_close(pcm); pcm = NULL; return -1; } - - //now we can be a bit flexible with the buffer size and the sample-rate... - - int upsample; - for (upsample = 1; upsample < upsample_max; ++upsample) - { - frame_rate = rate0 * upsample; - - if ( 0 > snd_pcm_hw_params_any(pcm, hw)) { ERROR_HERE; goto open_error;} - - //first do the compulsory steps... interleaved float, 2 channel - if ( 0 > snd_pcm_hw_params_set_rate_resample(pcm, hw, 0)) { ERROR_HERE; goto open_error;} - if ( 0 > snd_pcm_hw_params_test_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED)){ ERROR_HERE; goto open_error;} - if ( 0 > snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED)){ ERROR_HERE; goto open_error;} - if ( 0 > snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_FLOAT)) { ERROR_HERE; goto open_error;} - if ( 0 > snd_pcm_hw_params_set_format(pcm, hw, SND_PCM_FORMAT_FLOAT)) { ERROR_HERE; goto open_error;} - if ( 0 > snd_pcm_hw_params_set_channels(pcm, hw, 2)) { ERROR_HERE; goto open_error;} - - IF_DEBUG(1) fprintf(_debug, "testing rate : %i\t", frame_rate); - if ( snd_pcm_hw_params_test_rate(pcm, hw, frame_rate, 0)) - { - fprintf(_debug, "failed.\n"); - continue; - } - else - { - IF_DEBUG(1) fprintf(_debug, "success! setting rate : %i\n", frame_rate); - if (0 > snd_pcm_hw_params_set_rate(pcm, hw, frame_rate, 0)) { ERROR_HERE; goto open_error;} - - snd_pcm_uframes_t minb=0, maxb= 0; - int mind=0, maxd=0; - snd_pcm_hw_params_get_period_size_min(hw, &minb,&mind); - snd_pcm_hw_params_get_period_size_max(hw, &maxb,&maxd); - IF_DEBUG(1) fprintf(_debug, "FYI: period size range is [%li/%i,%li/%i]\n", minb,mind, maxb, maxd); - - assert(mind == 0); //rate_resample 0 makes this true right? - assert(maxd == 0); //rate_resample 0 makes this true right? - - if (period0 < minb) - { - IF_DEBUG(1) fprintf(_debug, "requested period size (%li) < min (%li), adjusting to min\n", period_size, minb); - period_size = minb; - } - else if (period0 > maxb) - { - IF_DEBUG(1) fprintf(_debug, "requested period size (%li) < max (%li), adjusting to min\n", period_size, maxb); - period_size = maxb; - } - else - { - period_size = period0; - } - - IF_DEBUG(1) fprintf(_debug, "testing period size : %li\n", period_size); - if ( 0 > snd_pcm_hw_params_test_period_size(pcm, hw, period_size, 0)){ ERROR_HERE; goto open_error;} - - - IF_DEBUG(1) fprintf(_debug, "setting period size : %li\n", period_size); - if ( 0 > snd_pcm_hw_params_set_period_size(pcm, hw, period_size, 0)){ ERROR_HERE; goto open_error;} - - IF_DEBUG(1) fprintf(_debug, "setting buffer size : %i * %li = %li\n", p_per_buff, period_size, p_per_buff * period_size); - if ( 0 > snd_pcm_hw_params_set_buffer_size(pcm, hw, p_per_buff*period_size)) { ERROR_HERE; goto open_error;} - - break; - } - } - - if (upsample_max == upsample) { ERROR_HERE; goto open_error; } - - if (0 > snd_pcm_hw_params(pcm, hw)) { ERROR_HERE; goto open_error; } - - snd_pcm_hw_params_free (hw); - return 0; - -open_error: - snd_pcm_hw_params_free (hw); - snd_pcm_close(pcm); - pcm = NULL; - return -1; - } - void close(int drain = 0) - { - if (!pcm) - { - IF_DEBUG(2) fprintf(_debug, "WARNING: attempt to close already-closed pcm\n"); - return; - } - IF_DEBUG(1) fprintf(_debug, "INFO: closing pcm device\n"); - if (drain) snd_pcm_drain(pcm); - snd_pcm_close(pcm); - pcm = NULL; - } - void prepare() - { - if (!pcm) - { - IF_DEBUG(0) fprintf(_debug, "ERROR: attempt to prepare a closed pcm\n"); - return; - } - if (0 > snd_pcm_prepare(pcm)) { ERROR_HERE; } - } - int write(snd_pcm_uframes_t frame_count, float * frame_data) - { - if (!pcm) - { - IF_DEBUG(0) fprintf(_debug, "ERROR: attempt to write a closed pcm\n"); - return -1; - } - int err; - err = snd_pcm_writei (pcm, frame_data, frame_count ); - if (err == (signed)frame_count) return 0; //success - - assert(err < 0); - - const char * msg = NULL; - snd_pcm_state_t state = snd_pcm_state(pcm); - switch (state) - { - case SND_PCM_STATE_OPEN: msg = "open"; break; - case SND_PCM_STATE_SETUP: msg = "setup"; break; - case SND_PCM_STATE_PREPARED:msg = "prepared"; break; - case SND_PCM_STATE_RUNNING: msg = "running"; break; - case SND_PCM_STATE_XRUN: msg = "xrun"; break; - case SND_PCM_STATE_DRAINING: msg = "draining"; break; - case SND_PCM_STATE_PAUSED: msg = "paused"; break; - case SND_PCM_STATE_SUSPENDED: msg = "suspended"; break; - case SND_PCM_STATE_DISCONNECTED: msg = "disconnected"; break; - } - if (_debug && (VERBOSE > 1)) fprintf (_debug, "WARNING: write failed (%s)\tstate = %s\ttime=%lf\n", snd_strerror (err), msg, pytime(NULL)); - if (0 > snd_pcm_recover(pcm, err, 0)) { ERROR_HERE; return err;} - if (0 > snd_pcm_prepare(pcm)) { ERROR_HERE; return err;} - return 1; //warning - } -}; struct TamTamSound { /** the id of an running sound-rendering thread, or NULL */ @@ -521,7 +345,12 @@ struct TamTamSound unsigned int period_per_buffer; int up_ratio; - SystemStuff sys_stuff; + log_t * ll; +#if NEWAUDIO + AlsaStuff * sys_stuff; +#else + SystemStuff * sys_stuff; +#endif TamTamSound(char * orc, snd_pcm_uframes_t period0, unsigned int ppb) : ThreadID(NULL), PERF_STATUS(STOP), csound(NULL), @@ -531,17 +360,31 @@ struct TamTamSound period0(period0), period_per_buffer(ppb), up_ratio(0), - sys_stuff() - { - if (0 > sys_stuff.open(csound_frame_rate, 4, period0, period_per_buffer)) - { - return; - } - sys_stuff.close(0); - up_ratio = sys_stuff.frame_rate / csound_frame_rate; - csound_period_size = (sys_stuff.period_size % up_ratio == 0) - ? sys_stuff.period_size / up_ratio + ll( new log_t(_debug, VERBOSE) ), + sys_stuff(NULL) + { +#if NEWAUDIO + sys_stuff = new AlsaStuff( "default", "default", SND_PCM_FORMAT_FLOAT, 2, csound_frame_rate, period0, 4, ll); + if (! sys_stuff->good_to_go ) return; + up_ratio = sys_stuff->rate / csound_frame_rate; + csound_period_size = (sys_stuff->period_size % up_ratio == 0) + ? sys_stuff->period_size / up_ratio : csound_ksmps * 4; + delete sys_stuff; + sys_stuff=NULL; +#else + sys_stuff = new SystemStuff(ll); + if (0 > sys_stuff->open(csound_frame_rate, 4, period0, period_per_buffer)) + { + return; + } + sys_stuff->close(0); + up_ratio = sys_stuff->rate / csound_frame_rate; + csound_period_size = (sys_stuff->period_size % up_ratio == 0) + ? sys_stuff->period_size / up_ratio + : csound_ksmps * 4; + +#endif csound = csoundCreate(NULL); int argc=3; @@ -576,6 +419,8 @@ struct TamTamSound csoundDestroy(csound); } if (_debug && (VERBOSE > 2)) fprintf(_debug, "TamTam aclient destroyed\n"); + if (sys_stuff) delete sys_stuff; + delete ll; } uintptr_t thread_fn() { @@ -588,30 +433,44 @@ struct TamTamSound if (_debug && (VERBOSE > 2)) fprintf(_debug, "INFO: nsamples = %li nframes = %li\n", csound_nsamples, csound_nframes); - if (0 > sys_stuff.open(csound_frame_rate, 4, period0, period_per_buffer)) +#if NEWAUDIO + sys_stuff = new AlsaStuff( "default", "default", SND_PCM_FORMAT_FLOAT, 2, csound_frame_rate, period0, 4, ll); + if (!sys_stuff->good_to_go) { - IF_DEBUG(0) fprintf(_debug, "ERROR: failed to open alsa device, thread abort\n"); + delete sys_stuff; return 1; } - assert(up_ratio = sys_stuff.frame_rate / csound_frame_rate); - - float *upbuf = new float[ sys_stuff.period_size * nchannels ]; //2 channels + assert(up_ratio = sys_stuff->rate / csound_frame_rate); +#else + if (0 > sys_stuff->open(csound_frame_rate, 4, period0, period_per_buffer)) + { + IF_DEBUG(0) fprintf(_debug, "ERROR: failed to open alsa device, thread abort\n"); + return 1; + } + + assert(up_ratio = sys_stuff->rate / csound_frame_rate); +#endif + + float *upbuf = new float[ sys_stuff->period_size * nchannels ]; //2 channels int cbuf_pos = csound_nframes; float *cbuf = NULL; - unsigned up_pos = 0; + int up_pos = 0; int ratio_pos = 0; - sys_stuff.setscheduler(); //it might work... - while (PERF_STATUS == CONTINUE) { - if (sys_stuff.period_size == (unsigned)csound_nframes ) + if ((signed)sys_stuff->period_size == csound_nframes ) { + //if (0 > sys_stuff->readbuf((char*)csoundGetInputBuffer(csound))) break; if (csoundPerformBuffer(csound)) break; - if (0 > sys_stuff.write(sys_stuff.period_size, csoundGetOutputBuffer(csound))) break; +#if NEWAUDIO + if (0 > sys_stuff->writebuf((char*)csoundGetOutputBuffer(csound))) break; +#else + if (0 > sys_stuff->writebuf(csound_nframes,csoundGetOutputBuffer(csound))) break; +#endif } - else + else //fill one period of audio buffer data by 0 or more calls to csound { up_pos = 0; int messed = 0; @@ -620,7 +479,7 @@ struct TamTamSound if (cbuf_pos == csound_nframes) { cbuf_pos = 0; - if (csoundPerformBuffer(csound)) {messed = 1;break;} + if (csoundPerformBuffer(csound)) { messed = 1;break;} cbuf = csoundGetOutputBuffer(csound); } upbuf[2*up_pos+0] = cbuf[cbuf_pos*2+0]; @@ -632,11 +491,15 @@ struct TamTamSound ++cbuf_pos; } - if (++up_pos == sys_stuff.period_size) break; + if (++up_pos == (signed)sys_stuff->period_size) break; } - if (messed || (up_pos != sys_stuff.period_size)) break; + if (messed || (up_pos != (signed)sys_stuff->period_size)) break; - if (0 > sys_stuff.write(sys_stuff.period_size, upbuf)) break; +#if NEWAUDIO + if (0 > sys_stuff->writebuf((char*)upbuf)) break; +#else + if (0 > sys_stuff->writebuf(csound_nframes,csoundGetOutputBuffer(csound))) break; +#endif } if (thread_playloop) @@ -646,10 +509,17 @@ struct TamTamSound ++nloops; } - sys_stuff.close(1); +#if NEWAUDIO + delete sys_stuff; + sys_stuff = NULL; +#else + sys_stuff->close(1); +#endif + delete [] upbuf; if (_debug && (VERBOSE > 2)) fprintf(_debug, "INFO: returning from performance thread\n"); return 0; } + uintptr_t read_thread_fn() static uintptr_t csThread(void *clientData) { return ((TamTamSound*)clientData)->thread_fn(); @@ -664,8 +534,10 @@ struct TamTamSound { PERF_STATUS = CONTINUE; ThreadID = csoundCreateThread(csThread, (void*)this); + ll->printf( "INFO(%s:%i) aclient launching performance thread (%p)\n", __FILE__, __LINE__, ThreadID ); return 0; } + ll->printf( "INFO(%s:%i) skipping duplicate request to launch a thread\n", __FILE__, __LINE__ ); return 1; } int stop() @@ -677,10 +549,10 @@ struct TamTamSound if (ThreadID) { PERF_STATUS = STOP; - if (_debug && (VERBOSE > 2)) fprintf(_debug, "INFO: aclient joining performance thread\n"); + ll->printf( "INFO(%s:%i) aclient joining performance thread\n", __FILE__, __LINE__ ); uintptr_t rval = csoundJoinThread(ThreadID); - if (rval) - if (_debug && (VERBOSE > 0)) fprintf(_debug, "WARNING: thread returned %zu\n", rval); + ll->printf( "INFO(%s:%i) ... joined\n", __FILE__, __LINE__ ); + if (rval) ll->printf( "WARNING: thread returned %zu\n", rval); ThreadID = NULL; return 0; } @@ -854,9 +726,15 @@ DECL(sc_initialize) //(char * csd) return NULL; } if ( log_file[0] ) + { _debug = fopen(log_file,"w"); + if (_debug==NULL) fprintf(stderr, "Logging disabled due to error in fopen(%s) \n", log_file); + } else + { _debug = NULL; + fprintf(stderr, "Logging disabled on purpose\n"); + } sc_tt = new TamTamSound(str, period, ppb); atexit(&cleanup); if (sc_tt->good()) diff --git a/Util/Clooper/audio.cpp b/Util/Clooper/audio.cpp new file mode 100644 index 0000000..f757f31 --- /dev/null +++ b/Util/Clooper/audio.cpp @@ -0,0 +1,681 @@ +/* + * Latency test program + * + * Author: Jaroslav Kysela <perex@suse.cz> + * + * This small demo program can be used for measuring latency between + * capture and playback. This latency is measured from driver (diff when + * playback and capture was started). Scheduler is set to SCHED_RR. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sched.h> +#include <errno.h> +#include <getopt.h> +#include <sys/time.h> +#include <math.h> + +#include <string> +#include <alsa/asoundlib.h> + +#define ERROR_HERE ll->printf("ERROR_HERE: %s %i\n", __FILE__, __LINE__); + +struct SystemStuff +{ + log_t * ll; + + snd_pcm_t *phandle, *chandle; + snd_pcm_uframes_t period_size; + unsigned int rate; + + float * bonusbuf; + unsigned bonuspos; + + SystemStuff(log_t * ll) : ll(ll), phandle(NULL), chandle(NULL), period_size(0), rate(0), bonusbuf( NULL ) + { + bonusbuf = new float[16000 * 2]; + bonuspos = 0; + } + ~SystemStuff() + { + delete[] bonusbuf; + if (phandle) close(0); + } + + void setscheduler(void) + { + struct sched_param sched_param; + + if (sched_getparam(0, &sched_param) < 0) { + ll->printf( "Scheduler getparam failed...\n"); + return; + } + sched_param.sched_priority = sched_get_priority_max(SCHED_RR); + if (!sched_setscheduler(0, SCHED_RR, &sched_param)) { + ll->printf( "Scheduler set to Round Robin with priority %i...\n", sched_param.sched_priority); + return; + } + ll->printf( "!!!Scheduler set to Round Robin with priority %i FAILED!!!\n", sched_param.sched_priority); + } + + int open(unsigned int rate0, int upsample_max, snd_pcm_uframes_t period0, unsigned int p_per_buff) + { + snd_pcm_hw_params_t *hw; + + if (phandle) + { + ll->printf( "ERROR: open called twice! First close the sound device\n"); + return -1; + } + + if ( 0 > snd_pcm_open(&phandle, "default", SND_PCM_STREAM_PLAYBACK, 0)) { ERROR_HERE; return -1; } + if ( 0 > snd_pcm_open(&chandle, "default", SND_PCM_STREAM_CAPTURE, 0)) { ERROR_HERE; return -1; } + if ( 0 > snd_pcm_hw_params_malloc(&hw)) { ERROR_HERE; snd_pcm_close(phandle); phandle = NULL; return -1; } + + //now we can be a bit flexible with the buffer size and the sample-rate... + + int upsample; + for (upsample = 1; upsample < upsample_max; ++upsample) + { + rate = rate0 * upsample; + + if ( 0 > snd_pcm_hw_params_any(phandle, hw)) { ERROR_HERE; goto open_error;} + + //first do the compulsory steps... interleaved float, 2 channel + if ( 0 > snd_pcm_hw_params_set_rate_resample(phandle, hw, 0)) { ERROR_HERE; goto open_error;} + if ( 0 > snd_pcm_hw_params_test_access(phandle, hw, SND_PCM_ACCESS_RW_INTERLEAVED)){ ERROR_HERE; goto open_error;} + if ( 0 > snd_pcm_hw_params_set_access(phandle, hw, SND_PCM_ACCESS_RW_INTERLEAVED)){ ERROR_HERE; goto open_error;} + if ( 0 > snd_pcm_hw_params_test_format(phandle, hw, SND_PCM_FORMAT_FLOAT)) { ERROR_HERE; goto open_error;} + if ( 0 > snd_pcm_hw_params_set_format(phandle, hw, SND_PCM_FORMAT_FLOAT)) { ERROR_HERE; goto open_error;} + if ( 0 > snd_pcm_hw_params_set_channels(phandle, hw, 2)) { ERROR_HERE; goto open_error;} + + if ( snd_pcm_hw_params_test_rate(phandle, hw, rate, 0)) + { + ll->printf("test_rate failed( %i\n", rate); + continue; + } + else + { + ll->printf(1, "success! setting rate : %i\n", rate); + if (0 > snd_pcm_hw_params_set_rate(phandle, hw, rate, 0)) { ERROR_HERE; goto open_error;} + + snd_pcm_uframes_t minb=0, maxb= 0; + int mind=0, maxd=0; + snd_pcm_hw_params_get_period_size_min(hw, &minb,&mind); + snd_pcm_hw_params_get_period_size_max(hw, &maxb,&maxd); + ll->printf(2, "FYI: period size range is [%li/%i,%li/%i]\n", minb,mind, maxb, maxd); + + assert(mind == 0); //rate_resample 0 makes this true right? + assert(maxd == 0); //rate_resample 0 makes this true right? + + if (period0 < minb) + { + ll->printf(1, "requested period size (%li) < min (%li), adjusting to min\n", period_size, minb); + period_size = minb; + } + else if (period0 > maxb) + { + ll->printf(2, "requested period size (%li) < max (%li), adjusting to min\n", period_size, maxb); + period_size = maxb; + } + else + { + period_size = period0; + } + + ll->printf(1, "testing period size : %li\n", period_size); + if ( 0 > snd_pcm_hw_params_test_period_size(phandle, hw, period_size, 0)){ ERROR_HERE; goto open_error;} + + + ll->printf(1, "setting period size : %li\n", period_size); + if ( 0 > snd_pcm_hw_params_set_period_size(phandle, hw, period_size, 0)){ ERROR_HERE; goto open_error;} + + ll->printf(1, "setting buffer size : %i * %li = %li\n", p_per_buff, period_size, p_per_buff * period_size); + if ( 0 > snd_pcm_hw_params_set_buffer_size(phandle, hw, p_per_buff*period_size)) { ERROR_HERE; goto open_error;} + + break; + } + } + + if (upsample_max == upsample) { ERROR_HERE; goto open_error; } + + if (0 > snd_pcm_hw_params(phandle, hw)) { ERROR_HERE; goto open_error; } + if (0 > snd_pcm_hw_params(chandle, hw)) { ERROR_HERE; goto open_error; } + + snd_pcm_hw_params_free (hw); + return 0; + +open_error: + snd_pcm_hw_params_free (hw); + snd_pcm_close(phandle); + phandle = NULL; + return -1; + } + void close(int drain = 0) + { + if (!phandle) + { + ll->printf(0, "WARNING: attempt to close already-closed pcm\n"); + return; + } + ll->printf(1, "INFO: closing phandle device\n"); + if (drain) snd_pcm_drain(phandle); + snd_pcm_close(phandle); + snd_pcm_close(chandle); + phandle = NULL; + chandle = NULL; + } + void prepare() + { + if (!phandle) + { + ll->printf(0, "ERROR: attempt to prepare a closed pcm\n"); + return; + } + if (0 > snd_pcm_prepare(phandle)) { ERROR_HERE; } + } + int writebuf(snd_pcm_uframes_t frame_count, float * frame_data) + { + if (!phandle) + { + ll->printf(0, "ERROR: attempt to write a closed phandle\n"); + return -1; + } + int err; + err = snd_pcm_writei (phandle, frame_data, frame_count ); + if (err == (signed)frame_count) return 0; //success + + assert(err < 0); + + const char * msg = NULL; + snd_pcm_state_t state = snd_pcm_state(phandle); + switch (state) + { + case SND_PCM_STATE_OPEN: msg = "open"; break; + case SND_PCM_STATE_SETUP: msg = "setup"; break; + case SND_PCM_STATE_PREPARED:msg = "prepared"; break; + case SND_PCM_STATE_RUNNING: msg = "running"; break; + case SND_PCM_STATE_XRUN: msg = "xrun"; break; + case SND_PCM_STATE_DRAINING: msg = "draining"; break; + case SND_PCM_STATE_PAUSED: msg = "paused"; break; + case SND_PCM_STATE_SUSPENDED: msg = "suspended"; break; + case SND_PCM_STATE_DISCONNECTED: msg = "disconnected"; break; + } + ll->printf(1, "WARNING: write failed (%s)\tstate = %s\ttime=%lf\n", snd_strerror (err), msg, pytime(NULL)); + if (0 > snd_pcm_recover(phandle, err, 0)) { ERROR_HERE; return err;} + if (0 > snd_pcm_prepare(phandle)) { ERROR_HERE; return err;} + return 1; //warning + } + int readbuf(snd_pcm_uframes_t frame_count, float * frame_data) + { + int tries=0; + int err=1; + while (err && (tries<2)) + { + ++tries; + err = snd_pcm_readi (chandle, frame_data, frame_count ); + if (err < 0) + { + const char * msg = NULL; + snd_pcm_state_t state = snd_pcm_state(chandle); + switch (state) + { + case SND_PCM_STATE_OPEN: msg = "open"; break; + case SND_PCM_STATE_SETUP: msg = "setup"; break; + case SND_PCM_STATE_PREPARED:msg = "prepared"; break; + case SND_PCM_STATE_RUNNING: msg = "running"; break; + case SND_PCM_STATE_XRUN: msg = "xrun"; break; + case SND_PCM_STATE_DRAINING: msg = "draining"; break; + case SND_PCM_STATE_PAUSED: msg = "paused"; break; + case SND_PCM_STATE_SUSPENDED: msg = "suspended"; break; + case SND_PCM_STATE_DISCONNECTED: msg = "disconnected"; break; + } + ll->printf(1, "WARNING: read failed (%s)\tstate = %s\ttime=%lf\n", snd_strerror (err), msg, pytime(NULL)); + if (0 > snd_pcm_recover(chandle, err, 0)) { ERROR_HERE; return err;} + if (0 > snd_pcm_prepare(chandle)) { ERROR_HERE; return err;} + } + } + if (0) + { + float a = 0.0; + for (unsigned i = 0; i < frame_count; ++i) + { + a = a + frame_data[i] * frame_data[i]; + } + fprintf(stderr, "%lf %i\n", a, err); + } + return (err == (signed)frame_count) ? 0 : err; + } +}; +#undef ERROR_HERE + +struct AlsaStuff +{ + bool good_to_go; + std::string pdevice, cdevice; + snd_pcm_format_t format; + int rate; + int channels; + int buffer_size; + int period_size; + snd_output_t *output; + snd_pcm_t *phandle, *chandle; + log_t *ll; + int frame_bytes; + int allow_resample; + int streams_linked; + + snd_pcm_hw_params_t *pt_params, *ct_params; /* templates with rate, format and channels */ + snd_pcm_hw_params_t *p_params, *c_params; + snd_pcm_sw_params_t *p_swparams, *c_swparams; + + AlsaStuff( const char * pdev, const char * cdev, snd_pcm_format_t fmt, int chnl, int r0, int p0, int upsample_max, log_t * ll) + : good_to_go(false), + pdevice(pdev), + cdevice(cdev), + format(fmt), + rate(0), + channels(chnl), + buffer_size(0), + period_size(0), + phandle(NULL), chandle(NULL), + ll(ll), + frame_bytes((snd_pcm_format_width(format) / 8) * channels), + allow_resample(0) + { + int err; + snd_pcm_uframes_t p_size, c_size, p_psize, c_psize; + unsigned int p_time, c_time; + + snd_pcm_hw_params_alloca(&p_params); + snd_pcm_hw_params_alloca(&c_params); + snd_pcm_hw_params_alloca(&pt_params); + snd_pcm_hw_params_alloca(&ct_params); + snd_pcm_sw_params_alloca(&p_swparams); + snd_pcm_sw_params_alloca(&c_swparams); + + + if ((err = snd_output_stdio_attach(&output, ll->_file, 0)) < 0) { + ll->printf("Output failed: %s\n", snd_strerror(err)); + return; + } + + setscheduler(); + + if ((err = snd_pcm_open(&phandle, pdevice.c_str(), SND_PCM_STREAM_PLAYBACK, 0 )) < 0) { + ll->printf("Playback open error: %s\n", snd_strerror(err)); + return; + } + if ((err = snd_pcm_open(&chandle, cdevice.c_str(), SND_PCM_STREAM_CAPTURE, 0 )) < 0) { + ll->printf("Record open error: %s\n", snd_strerror(err)); + return; + } + + int upsample=0; + while(upsample < upsample_max) + { + ++upsample; + + rate += r0; + period_size += p0; + + // set stream params + if ((err = setparams_stream(phandle, pt_params, "playback")) < 0) { + ll->printf( "Unable to set parameters for playback stream: %s\n", snd_strerror(err)); + continue; + } + if ((err = setparams_stream(chandle, ct_params, "capture")) < 0) { + ll->printf("Unable to set parameters for playback stream: %s\n", snd_strerror(err)); + continue; + } + + // set buffer params + + if ((err = setparams_bufsize(phandle, p_params, pt_params, period_size, "playback")) < 0) { + printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); + continue; + } + if ((err = setparams_bufsize(chandle, c_params, ct_params, period_size, "capture")) < 0) { + printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); + continue; + } + + snd_pcm_hw_params_get_period_size(p_params, &p_psize, NULL); + if (p_psize < (unsigned int)period_size) continue; + + snd_pcm_hw_params_get_period_size(c_params, &c_psize, NULL); + if (c_psize < (unsigned int)period_size) continue; + + snd_pcm_hw_params_get_period_time(p_params, &p_time, NULL); + snd_pcm_hw_params_get_period_time(c_params, &c_time, NULL); + if (p_time != c_time) continue; + + snd_pcm_hw_params_get_buffer_size(p_params, &p_size); + if (p_psize * 2 < p_size) continue; + + snd_pcm_hw_params_get_buffer_size(c_params, &c_size); + if (c_psize * 2 < c_size) continue; + + if ((err = setparams_set(phandle, p_params, p_swparams, "playback")) < 0) { + printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); + continue; + } + if ((err = setparams_set(chandle, c_params, c_swparams, "capture")) < 0) { + printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); + continue; + } + break; + } + + if (upsample == upsample_max) return; + + ll->printf("Preparing audio devices\n"); + if ((err = snd_pcm_prepare(phandle)) < 0) { + printf("Prepare playback error: %s\n", snd_strerror(err)); + return; + } + if ((err = snd_pcm_prepare(chandle)) < 0) { + printf("Prepare capture error: %s\n", snd_strerror(err)); + return; + } + good_to_go = true; + snd_pcm_dump(phandle, output); + snd_pcm_dump(chandle, output); + char * silence = (char*)malloc(period_size * frame_bytes); + if (snd_pcm_format_set_silence(format, silence, period_size*channels) < 0) { + ll->printf( "silence error\n"); + } + if (writebuf(silence) < 0) { + ll->printf( "write error\n"); + good_to_go=false; + } + if (writebuf(silence) < 0) { + ll->printf( "write error\n"); + good_to_go=false; + } + free(silence); + ll->printf("Starting audio devices\n"); + if ((err = snd_pcm_start(chandle)) < 0) { + ll->printf( "Go capture error: %s\n", snd_strerror(err)); + good_to_go=false; + return; + } + if ((err = snd_pcm_start(phandle)) < 0) { + ll->printf( "Go playback error: %s\n", snd_strerror(err)); + good_to_go=false; + return; + } + } + ~AlsaStuff() + { + snd_pcm_drop(chandle); + snd_pcm_drain(phandle); + snd_pcm_hw_free(phandle); + snd_pcm_hw_free(chandle); + snd_pcm_close(phandle); + snd_pcm_close(chandle); + } + + void setscheduler(void) + { + struct sched_param sched_param; + + if (sched_getparam(0, &sched_param) < 0) { + ll->printf( "Scheduler getparam failed...\n"); + return; + } + sched_param.sched_priority = sched_get_priority_max(SCHED_RR); + if (!sched_setscheduler(0, SCHED_RR, &sched_param)) { + ll->printf( "Scheduler set to Round Robin with priority %i...\n", sched_param.sched_priority); + return; + } + ll->printf( "!!!Scheduler set to Round Robin with priority %i FAILED!!!\n", sched_param.sched_priority); + } + long readbuf(char *buf) + { + return 0; + if (!good_to_go) return -1; + long frames = period_size; + while( frames ) + { + ll->printf( "reading %li\n", frames); + long r = snd_pcm_readi(chandle, buf, frames); + if (r < 0) + { + ll->printf( "error in snd_pcm_readi(): %s\n", snd_strerror(r)); + return r; + } + buf += r * frame_bytes; + frames -= r; + } + return 0; + } + long writebuf(const char *buf) + { + long frames = period_size; + if (!good_to_go) return -1; + while ( frames ) { + ll->printf("snd_pcm_writei ! (%li)\n", frames); + long r = snd_pcm_writei(phandle, buf, frames); + if (r == frames) break; + if (r >= 0) + { + ll->printf("snd_pcm_writei wrote only some of the frames! (%li)\n", r); + break; + } + + const char * msg = NULL; + snd_pcm_state_t state = snd_pcm_state(phandle); + switch (state) + { + case SND_PCM_STATE_OPEN: msg = "open"; break; + case SND_PCM_STATE_SETUP: msg = "setup"; break; + case SND_PCM_STATE_PREPARED:msg = "prepared"; break; + case SND_PCM_STATE_RUNNING: msg = "running"; break; + case SND_PCM_STATE_XRUN: msg = "xrun"; break; + case SND_PCM_STATE_DRAINING: msg = "draining"; break; + case SND_PCM_STATE_PAUSED: msg = "paused"; break; + case SND_PCM_STATE_SUSPENDED: msg = "suspended"; break; + case SND_PCM_STATE_DISCONNECTED: msg = "disconnected"; break; + } + ll->printf( "WARNING: write failed (%s)\tstate = %s\t\n", snd_strerror (r), msg); + if (0 > snd_pcm_recover(phandle, r, 0)) { ll->printf( "fuck\n"); return r;} + ll->printf( "made it end of recover... looping\n"); + if (0 > snd_pcm_prepare(phandle)) { ll->printf( "fuck\n"); return r;} + ll->printf( "made it end of writebuf... looping\n"); + } + return 0; + } + + int setparams_stream(snd_pcm_t *handle, snd_pcm_hw_params_t *params, const char *id) + { + int err; + unsigned int rrate=rate; + + err = snd_pcm_hw_params_any(handle, params); + if (err < 0) { + printf("Broken configuration for %s PCM: no configurations available: %s\n", snd_strerror(err), id); + return err; + } + err = snd_pcm_hw_params_set_rate_resample(handle, params, allow_resample); + if (err < 0) { + printf("Resample setup failed for %s (val %i): %s\n", id, allow_resample, snd_strerror(err)); + return err; + } + err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); + if (err < 0) { + printf("Access type not available for %s: %s\n", id, snd_strerror(err)); + return err; + } + err = snd_pcm_hw_params_set_format(handle, params, format); + if (err < 0) { + printf("Sample format not available for %s: %s\n", id, snd_strerror(err)); + return err; + } + err = snd_pcm_hw_params_set_channels(handle, params, channels); + if (err < 0) { + printf("Channels count (%i) not available for %s: %s\n", channels, id, snd_strerror(err)); + return err; + } + err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); + if (err < 0) { + printf("Rate %iHz not available for %s: %s\n", rate, id, snd_strerror(err)); + return err; + } + if ((int)rrate != rate) { + printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err); + return -EINVAL; + } + return 0; + } + + int setparams_bufsize(snd_pcm_t *handle, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *tparams, + snd_pcm_uframes_t bufsize, + const char *id) + { + int err; + snd_pcm_uframes_t periodsize; + + snd_pcm_hw_params_copy(params, tparams); + periodsize = bufsize * 2; + err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &periodsize); + if (err < 0) { + printf("Unable to set buffer size %li for %s: %s\n", bufsize * 2, id, snd_strerror(err)); + return err; + } + if (period_size > 0) + periodsize = period_size; + else + periodsize /= 2; + err = snd_pcm_hw_params_set_period_size_near(handle, params, &periodsize, 0); + if (err < 0) { + printf("Unable to set period size %li for %s: %s\n", periodsize, id, snd_strerror(err)); + return err; + } + return 0; + } + + int setparams_set(snd_pcm_t *handle, + snd_pcm_hw_params_t *params, + snd_pcm_sw_params_t *swparams, + const char *id) + { + int err; + + err = snd_pcm_hw_params(handle, params); + if (err < 0) { + printf("Unable to set hw params for %s: %s\n", id, snd_strerror(err)); + return err; + } + err = snd_pcm_sw_params_current(handle, swparams); + if (err < 0) { + printf("Unable to determine current swparams for %s: %s\n", id, snd_strerror(err)); + return err; + } + err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0x7fffffff); + if (err < 0) { + printf("Unable to set start threshold mode for %s: %s\n", id, snd_strerror(err)); + return err; + } + err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1); + if (err < 0) { + printf("Unable to set transfer align for %s: %s\n", id, snd_strerror(err)); + return err; + } + err = snd_pcm_sw_params(handle, swparams); + if (err < 0) { + printf("Unable to set sw params for %s: %s\n", id, snd_strerror(err)); + return err; + } + return 0; + } + + void showstat(snd_pcm_t *handle, size_t frames) + { + int err; + snd_pcm_status_t *status; + + snd_pcm_status_alloca(&status); + if ((err = snd_pcm_status(handle, status)) < 0) { + printf("Stream status error: %s\n", snd_strerror(err)); + exit(0); + } + printf("*** frames = %li ***\n", (long)frames); + snd_pcm_status_dump(status, output); + snd_pcm_status_free(status); + } +}; + +typedef char frame_t; + +struct Upsampler +{ + AlsaStuff * dev; + int ratio; + int blocklen; + + frame_t * rbuf; + frame_t * wbuf; + frame_t * rptr; + frame_t * wptr; + + Upsampler( AlsaStuff * dev, int ratio, int blocklen ) + : dev(dev), + ratio(ratio), + blocklen(blocklen), + rbuf( new frame_t[dev->period_size * dev->frame_bytes ]), + wbuf( new frame_t[dev->period_size * dev->frame_bytes ]), + rptr(rbuf), + wptr(wbuf) + { + } + ~Upsampler() + { + delete[] rbuf; + delete[] wbuf; + } + //store blocklen * dev->frame_bytes in framebuf + long readbuf(frame_t * framebuf) + { + if ((ratio == 1) && (blocklen == dev->period_size)) + { + } + else + { + } + return 0; + } + //write blocklen * dev->frame_bytes in framebuf + long writebuf(const frame_t * __restrict__ framebuf) + { + if ((ratio == 1) && (blocklen == dev->period_size)) + { + } + else + { + } + return 0; + } +}; + + diff --git a/Util/Clooper/log.cpp b/Util/Clooper/log.cpp new file mode 100644 index 0000000..1749721 --- /dev/null +++ b/Util/Clooper/log.cpp @@ -0,0 +1,47 @@ + +#include <stdarg.h> +#include <stdio.h> + +struct log_t +{ + FILE * _file; + int _level; + int _close; + + log_t(const char * logpath, int level = 0) : _file(NULL), _level(level), _close(1) + { + _file = fopen(logpath, "w"); + if (!_file) + { + fprintf(stderr, "Failed to open log file for writing: %s\n", logpath); + } + } + log_t(FILE * file, int level = 0): _file(file), _level(level), _close(0) + { + } + ~log_t() + { + if (_close && _file) fclose(_file); + } + void printf( const char * fmt, ... ) __attribute__(( format (printf, 2,3))) + { + if (!_file) return; + va_list ap; + va_start(ap,fmt); + ::vfprintf(_file, fmt, ap); + va_end(ap); + fflush(_file); + } + void printf( int level, const char * fmt, ... ) __attribute__(( format (printf, 3,4))) + { + if (level <= _level) + { + if (!_file) return; + va_list ap; + va_start(ap,fmt); + ::vfprintf(_file, fmt, ap); + va_end(ap); + fflush(_file); + } + } +}; diff --git a/Util/KeyboardWindow.py b/Util/KeyboardWindow.py index e9f00ea..4d67375 100644 --- a/Util/KeyboardWindow.py +++ b/Util/KeyboardWindow.py @@ -4,25 +4,41 @@ pygtk.require( '2.0' ) import gtk import random from ThemeWidgets import keyButton +import Config +KEY_MAP_PIANO = Config.KEY_MAP_PIANO class KeyboardWindow(gtk.Window): - def __init__(self, size = None): - gtk.Window.__init__(self , gtk.WINDOW_TOPLEVEL) - self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) + def __init__(self, size = None, pos = 0, popup = False): + if popup is False: + gtk.Window.__init__(self , gtk.WINDOW_TOPLEVEL) + else: + gtk.Window.__init__(self , gtk.WINDOW_POPUP) color = gtk.gdk.color_parse("#000000") self.modify_bg(gtk.STATE_NORMAL, color) - - self.connect("destroy",self.hide) + self.set_decorated(False) + + self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.ENTER_NOTIFY_MASK | gtk.gdk.KEY_PRESS_MASK) self.connect("key-press-event",self.handle_keypress) self.connect("key-release-event",self.handle_keyrelease) + self.connect("button-press-event",self.handle_mousePress) + self.connect("button-release-event",self.handle_mouseRelease) + self.connect("enter-notify-event",self.handle_enter) - if size == None: - self.PIXEL_SPACE = 15 - self.HEIGHT = 45 + self.size = size + self.pos = pos + self.popup = popup + self.set_pos(self.pos) + + if self.size == None: + self.pixel_space = 15 + self.height = 45 else: - self.PIXEL_SPACE = size - self.HEIGHT = 3* size + self.pixel_space = size + self.height = 3 * size + + self.draw() + def draw(self): self.rows = {} self.rows[1] = [(49,1), (10,3), (11,3), (12,3), (13,3), (14,3), (15,3), (16,3), (17,3), (18,3), (19,3), (20,3), (21,5)] self.rows[2] = [(23,3), (24,3), (25,3), (26,3), (27,3), (28,3), (29,3), (30,3), (31,3), (32,3), (33,3), (34,3), (35,4)] @@ -34,58 +50,125 @@ class KeyboardWindow(gtk.Window): self.btn_dic = {} + mainvbox = gtk.VBox() mainhbox = gtk.HBox() + #Main keyboard section vbox = gtk.VBox() for row in [1,2,3,4,5]: hbox = gtk.HBox() for key in self.rows[row]: - self.btn_dic[key[0]] = keyButton(self.PIXEL_SPACE * key[1], self.HEIGHT, [0,0,0], [0.5,0.5,0.5]) - self.btn_dic[key[0]].connect("enter",self.handle_mouseEnter) - self.btn_dic[key[0]].connect("leave",self.handle_mouseLeave) - hbox.pack_start(self.btn_dic[key[0]], padding = self.PIXEL_SPACE//2) - vbox.pack_start(hbox, padding = self.PIXEL_SPACE//2) + self.btn_dic[key[0]] = keyButton(self.pixel_space * key[1], self.height, [0,0,0], [0.5,0.5,0.5]) + hbox.pack_start(self.btn_dic[key[0]], padding = self.pixel_space//2) + vbox.pack_start(hbox, padding = self.pixel_space//2) mainhbox.pack_start(vbox) + #Right part of the keyboard right_vbox = gtk.VBox() right_tophbox = gtk.HBox() right_lowhbox = gtk.HBox() - self.btn_dic[self.right_section[0][0]] = keyButton(self.PIXEL_SPACE * self.right_section[0][1], self.HEIGHT, [0,0,0], [0.5,0.5,0.5]) - self.btn_dic[self.right_section[1][0]] = keyButton(self.PIXEL_SPACE * self.right_section[1][1][0], self.PIXEL_SPACE * self.right_section[1][1][1], [0,0,0], [0.5,0.5,0.5]) - self.btn_dic[self.right_section[2][0]] = keyButton(self.PIXEL_SPACE * self.right_section[2][1], self.HEIGHT, [0,0,0], [0.5,0.5,0.5]) - self.btn_dic[self.right_section[3][0]] = keyButton(self.PIXEL_SPACE * self.right_section[3][1], self.HEIGHT, [0,0,0], [0.5,0.5,0.5]) - self.btn_dic[self.right_section[4][0]] = keyButton(self.PIXEL_SPACE * self.right_section[4][1], self.HEIGHT, [0,0,0], [0.5,0.5,0.5]) - self.btn_dic[self.right_section[5][0]] = keyButton(self.PIXEL_SPACE * self.right_section[5][1], self.HEIGHT, [0,0,0], [0.5,0.5,0.5]) - - for key in self.right_section: - self.btn_dic[key[0]].connect("enter",self.handle_mouseEnter) - self.btn_dic[key[0]].connect("leave",self.handle_mouseLeave) + self.btn_dic[self.right_section[0][0]] = keyButton(self.pixel_space * self.right_section[0][1], self.height, [0,0,0], [0.5,0.5,0.5]) + self.btn_dic[self.right_section[1][0]] = keyButton(self.pixel_space * self.right_section[1][1][0], self.pixel_space * self.right_section[1][1][1], [0,0,0], [0.5,0.5,0.5]) + self.btn_dic[self.right_section[2][0]] = keyButton(self.pixel_space * self.right_section[2][1], self.height, [0,0,0], [0.5,0.5,0.5]) + self.btn_dic[self.right_section[3][0]] = keyButton(self.pixel_space * self.right_section[3][1], self.height, [0,0,0], [0.5,0.5,0.5]) + self.btn_dic[self.right_section[4][0]] = keyButton(self.pixel_space * self.right_section[4][1], self.height, [0,0,0], [0.5,0.5,0.5]) + self.btn_dic[self.right_section[5][0]] = keyButton(self.pixel_space * self.right_section[5][1], self.height, [0,0,0], [0.5,0.5,0.5]) - right_vbox.pack_start(self.btn_dic[self.right_section[0][0]], padding = self.PIXEL_SPACE//2) - right_vbox.pack_start(self.btn_dic[self.right_section[1][0]], padding = self.PIXEL_SPACE//2) - right_tophbox.pack_start(self.btn_dic[self.right_section[2][0]], padding = self.PIXEL_SPACE//2) - right_tophbox.pack_start(self.btn_dic[self.right_section[3][0]], padding = self.PIXEL_SPACE//2) - right_lowhbox.pack_start(self.btn_dic[self.right_section[4][0]], padding = self.PIXEL_SPACE//2) - right_lowhbox.pack_start(self.btn_dic[self.right_section[5][0]], padding = self.PIXEL_SPACE//2) - right_vbox.pack_start(right_tophbox, padding = self.PIXEL_SPACE//2) - right_vbox.pack_start(right_lowhbox, padding = self.PIXEL_SPACE//2) + right_vbox.pack_start(self.btn_dic[self.right_section[0][0]], padding = self.pixel_space//2) + right_vbox.pack_start(self.btn_dic[self.right_section[1][0]], padding = self.pixel_space//2) + right_tophbox.pack_start(self.btn_dic[self.right_section[2][0]], padding = self.pixel_space//2) + right_tophbox.pack_start(self.btn_dic[self.right_section[3][0]], padding = self.pixel_space//2) + right_lowhbox.pack_start(self.btn_dic[self.right_section[4][0]], padding = self.pixel_space//2) + right_lowhbox.pack_start(self.btn_dic[self.right_section[5][0]], padding = self.pixel_space//2) + right_vbox.pack_start(right_tophbox, padding = self.pixel_space//2) + right_vbox.pack_start(right_lowhbox, padding = self.pixel_space//2) + + #Mouse buttons + mouse_hbox = gtk.HBox() + self.btn_dic["left_mouse"] = keyButton(self.pixel_space * 6, self.pixel_space * 2, [0,0,0], [0.5,0.5,0.5]) + self.btn_dic["right_mouse"] = keyButton(self.pixel_space * 6, self.pixel_space * 2, [0,0,0], [0.5,0.5,0.5]) + mouse_hbox.pack_start(self.btn_dic["left_mouse"], False, False, padding = self.pixel_space//2) + mouse_hbox.pack_start(self.btn_dic["right_mouse"], False, False, padding = self.pixel_space//2) + + + #Enter and Leave connections + for key in self.btn_dic: + self.btn_dic[key].connect("enter",self.handle_mouseEnter) + self.btn_dic[key].connect("leave",self.handle_mouseLeave) mainhbox.pack_start(right_vbox) + mainvbox.pack_start(mainhbox) + mainvbox.pack_start(mouse_hbox, padding = self.pixel_space//2) + + self.add(mainvbox) + + def set_pos(self,_pos = 0): + width = self.get_screen().get_width() + height = self.get_screen().get_height() + win_width = self.get_size()[0] + win_height = self.get_size()[1] - self.add(mainhbox) + self.pos = _pos + + pos = [0,0] + pos[0] = (0, 0) + pos[1] = (width - win_width, height - win_height) + self.move(pos[self.pos][0],pos[self.pos][1]) + + def color_piano(self): + for key in KEY_MAP_PIANO: + self.btn_dic[key].set_fillcolor(1,1,1) + def handle_keypress(self,widget,event): - self.btn_dic[event.hardware_keycode].set_fillcolor(random.random(),random.random(),random.random()) + if event.hardware_keycode == 9: # Hide the keyboard with escape Key + self.hide_all() + elif event.hardware_keycode == 216: # Send a fake mouse event + self.btn_dic["left_mouse"].set_fillcolor(random.random(),random.random(),random.random()) + elif event.hardware_keycode == 133: # Send a fake mouse event + self.btn_dic["right_mouse"].set_fillcolor(random.random(),random.random(),random.random()) + else: + self.btn_dic[event.hardware_keycode].set_fillcolor(random.random(),random.random(),random.random()) def handle_keyrelease(self,widget,event): - self.btn_dic[event.hardware_keycode].set_fillcolor(0,0,0) + if KEY_MAP_PIANO.has_key(event.hardware_keycode): + self.btn_dic[event.hardware_keycode].set_fillcolor(1,1,1) + else: + self.btn_dic[event.hardware_keycode].set_fillcolor(0,0,0) + if event.hardware_keycode == 216 or event.hardware_keycode == 133: + self.btn_dic["left_mouse"].set_fillcolor(0,0,0) + self.btn_dic["right_mouse"].set_fillcolor(0,0,0) + + + def handle_mousePress(self,widget,event): + if event.button == 1: + self.btn_dic["left_mouse"].set_fillcolor(random.random(),random.random(),random.random()) + elif event.button == 3: + self.btn_dic["right_mouse"].set_fillcolor(random.random(),random.random(),random.random()) + + def handle_mouseRelease(self,widget,event): + if event.button == 1: + self.btn_dic["left_mouse"].set_fillcolor(0,0,0) + elif event.button == 3: + self.btn_dic["right_mouse"].set_fillcolor(0,0,0) def handle_mouseEnter(self,widget,event = None): widget.set_strokecolor(1,1,1) def handle_mouseLeave(self,widget,event = None): widget.set_strokecolor(0.5,0.5,0.5) + + def handle_enter(self,widget,event): + if self.popup is False: + return + if self.pos == 0: + self.set_pos(1) + else: + self.set_pos(0) + + def close(self,widget,event = None): + self.hide_all() diff --git a/Util/Trackpad.py b/Util/Trackpad.py index ea2990d..f46a62c 100644 --- a/Util/Trackpad.py +++ b/Util/Trackpad.py @@ -75,7 +75,7 @@ class Trackpad: def handle_keyPress(self,widget,event): if KEY_MAP_PIANO.has_key(event.hardware_keycode) and self.buttonPressed == False: gtk.gdk.Display.warp_pointer(self.display, self.screen, self.screen.get_width() / 2, self.screen.get_height() / 2) - gtk.gdk.pointer_grab(self.win.window, event_mask = gtk.gdk.POINTER_MOTION_MASK, cursor = self.invisible_cursor) + gtk.gdk.pointer_grab(self.win.window, event_mask = gtk.gdk.POINTER_MOTION_MASK)#, cursor = self.invisible_cursor) self.buttonPressed = True self.first_x = self.screen.get_width() / 2 self.first_y = self.screen.get_height() / 2 @@ -20,6 +20,7 @@ class Welcome(SubActivity): self.csnd = new_csound_client() self.noteDB = NoteDB.NoteDB() first = self.noteDB.addPage( -1, NoteDB.Page(4) ) + self.tooltips = gtk.Tooltips() actVBox = RoundVBox(fillcolor = Config.WS_BCK_COLOR, bordercolor = Config.WS_BCK_COLOR, radius = Config.PANEL_RADIUS) actHBox = gtk.HBox() @@ -32,6 +33,13 @@ class Welcome(SubActivity): actBtn.connect('clicked', self.onActivityBtnClicked, activity) actBtnBox.pack_start(actBtn,True,False,0) actHBox.pack_start(actBtnBox,True,False,0) + if activity == 'mini': + self.tooltips.set_tip(actBtn,'TamTamJam') + elif activity == 'edit': + self.tooltips.set_tip(actBtn,'TamTamEdit') + elif activity == 'synth': + self.tooltips.set_tip(actBtn,'SynthLab') + title = gtk.Image() title.set_from_file(Config.IMAGE_ROOT + 'TamTam.png') @@ -41,8 +49,10 @@ class Welcome(SubActivity): loadButton = ImageButton(Config.IMAGE_ROOT + 'load.png') loadButton.connect("clicked", self.handleLoad, None) buttonBox.pack_start(loadButton, False, False, 275) + self.tooltips.set_tip(loadButton,'Load TamTamEdit song') playStopButton = ImageToggleButton(Config.IMAGE_ROOT + 'miniplay.png', Config.IMAGE_ROOT + 'stop.png') + self.tooltips.set_tip(playStopButton,"Play loaded song") playStopButton.connect('button-press-event' , self.handlePlayButton) buttonBox.pack_start(playStopButton, False, False, 275) |