Skip to content

Commit bf0992a

Browse files
authored
Merge branch 'master' into fix_jwdj_EasyABC_103
2 parents b62c3b7 + 6623583 commit bf0992a

9 files changed

+2152
-378
lines changed

CHANGES

+6-1
Original file line numberDiff line numberDiff line change
@@ -637,4 +637,9 @@ different panes. Tie/untie option added for notes. Broken rhythm
637637
- New: file setting: ffmpeg
638638
- Several fixes to support newer Python versions. (thanks aupfred and all that contributed)
639639
- Updated xml2abc, abc2xml (aupfred)
640-
- Reenable note highlighting based on cursor position in editor (aupfred)
640+
- Reenable note highlighting based on cursor position in editor (aupfred)
641+
- Adapt to new version of abcmidi output (aupfred)
642+
- Fix playback of a selection on second page (aupfred)
643+
- Enable Midi playback for Mac based on Apple DLS Synthetiser thanks to mplay library (aupfred)
644+
- Fix Musicscore gets blank when clicking on the musicpanel (aupfred)
645+
- Updated about page and abc reference (aupfred)

easy_abc.py

+97-34
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ def unicode(s):
111111
# sys.stderr.write(traceback.format_exc())
112112
fluidsynth_available = False
113113

114+
#FAU:MIDIPLAY: On Mac, it is possible to interface directly to the Midi syntethiser of mac OS via mplay: https://github.com/jheinen/mplay
115+
# An adaptation is done to integrate with EasyABC
116+
if wx.Platform == "__WXMAC__":
117+
from mplaysmfplayer import *
118+
114119
from xml2abc_interface import xml_to_abc, abc_to_xml
115120
from midi2abc import midi_to_abc, Note, duration2abc
116121
from generalmidi import general_midi_instruments
@@ -1400,8 +1405,9 @@ def abc_to_midi(abc_code, settings, midi_file_name, add_follow_score_markers):
14001405

14011406
# 1.3.6 [SS] 2014-11-24
14021407
def add_abc2midi_options(cmd, settings, add_follow_score_markers):
1403-
if str2bool(settings['barfly']):
1404-
cmd.append('-BF')
1408+
#Force BF option flag to be at the last position according to jwdj/EasyABC#86 and sshlien/abcmidi#8
1409+
#if str2bool(settings['barfly']):
1410+
# cmd.append('-BF')
14051411
if str2bool(settings['nofermatas']):
14061412
cmd.append('-NFER')
14071413
if str2bool(settings['nograce']):
@@ -1414,6 +1420,8 @@ def add_abc2midi_options(cmd, settings, add_follow_score_markers):
14141420
# 1.3.6.4 [JWDJ] 2016-06-22
14151421
if add_follow_score_markers:
14161422
cmd.append('-EA')
1423+
if str2bool(settings['barfly']):
1424+
cmd.append('-BF')
14171425
return cmd
14181426

14191427

@@ -3980,14 +3988,24 @@ def __init__(self, parent, ID, app_dir, settings, options):
39803988
except Exception as e:
39813989
error_msg = traceback.format_exc()
39823990
self.mc = None
3991+
3992+
#FAU:MIDIPLAY: on Mac add the ability to interface to System Midi Synth via mplay in case fluidsynth not available or not configured with soundfont
3993+
if wx.Platform == "__WXMAC__" and self.mc is None:
3994+
try:
3995+
self.mc = MPlaySMFPlayer(self)
3996+
except:
3997+
error_msg = "Error on loading SMF Midi Player"
3998+
self.mc = None
39833999

39844000
if self.mc is None:
39854001
try:
39864002
backend = None
39874003
from wxmediaplayer import WxMediaPlayer
3988-
if wx.Platform == "__WXMAC__":
3989-
backend = wx.media.MEDIABACKEND_QUICKTIME
3990-
elif wx.Platform == "__WXMSW__":
4004+
#FAU:MIDIPLAY:The Quicktime interface do not manage MIDI File on latest version of Mac so keep only possibility on Windows
4005+
#if wx.Platform == "__WXMAC__":
4006+
# backend = wx.media.MEDIABACKEND_QUICKTIME
4007+
#elif wx.Platform == "__WXMSW__":
4008+
if wx.Platform == "__WXMSW__":
39914009
if platform.release() == 'XP':
39924010
backend = wx.media.MEDIABACKEND_DIRECTSHOW
39934011
else:
@@ -4292,13 +4310,15 @@ def GetAbcToPlay(self):
42924310
notes = get_notes_from_abc(text)
42934311
num_header_lines, first_note_line_index = self.get_num_extra_header_lines(tune)
42944312

4313+
#FAU: Seems not needed and issue when selecting not on a second page as it is considering all lines from first page as header. jwdj/EasyABC#100
4314+
#FAU: To be noted it was already removed from OnNoteSelectionChangedDesc
42954315
# workaround for the fact the abcm2ps returns incorrect row numbers
42964316
# check the row number of the first note and if it doesn't agree with the actual value
42974317
# then pretend that we have more or less extra header lines
4298-
if self.music_pane.current_page.notes: # 1.3.6.2 [JWdJ] 2015-02
4299-
actual_first_row = self.music_pane.current_page.notes[0][2]-1
4300-
correction = (actual_first_row - first_note_line_index)
4301-
num_header_lines += correction
4318+
#if self.music_pane.current_page.notes: # 1.3.6.2 [JWdJ] 2015-02
4319+
# actual_first_row = self.music_pane.current_page.notes[0][2]-1
4320+
# correction = (actual_first_row - first_note_line_index)
4321+
# num_header_lines += correction
43024322

43034323
temp = text.replace('\r\n', ' \n').replace('\r', '\n') # re.sub(r'\r\n|\r', '\n', text)
43044324
line_start_offset = [m.start(0) for m in re.finditer(r'(?m)^', temp)]
@@ -4474,12 +4494,17 @@ def OnMouseWheel(self, evt):
44744494
evt.Skip()
44754495

44764496
def play(self):
4497+
self.play_timer.Start(50)
44774498
if self.settings.get('follow_score', False) and self.current_page_index != 0:
44784499
self.select_page(0)
44794500
wx.CallAfter(self.mc.Play)
44804501

44814502
def stop_playing(self):
44824503
self.mc.Stop()
4504+
#FAU:remove highlighted notes
4505+
self.music_pane.draw_notes_highlighted(None)
4506+
#FAU:MIDIPLAY: play timer can be stopped no need to update progress slider
4507+
self.play_timer.Stop()
44834508
self.play_button.SetBitmap(self.play_bitmap)
44844509
self.play_button.Refresh()
44854510
self.progress_slider.SetValue(0)
@@ -4551,6 +4576,14 @@ def do_load_media_file(self, path):
45514576
if wx.Platform == "__WXMSW__" and platform.release() != 'XP':
45524577
# 1.3.6.3 [JWDJ] 2015-3 It seems mc.Play() triggers the OnMediaLoaded event
45534578
self.mc.Play() # does not start playing but triggers OnMediaLoaded event
4579+
#FAU:MIDIPLAY: added support for playback for Mac with SMF player For now kept apart from Windows
4580+
#FAU:MIDIPLAY: %%TODO%% verify if can be merged with preceeding if
4581+
#FAU:MIDIPLAY: 20250125 Not needed as correctly started based on OnMediaLoaded
4582+
#elif wx.Platform == "__WXMAC__":
4583+
# self.mc.Play()
4584+
#FAU:MIDIPLAY: Start timer to be able to have progress bar updated
4585+
# self.play_timer.Start(20)
4586+
# self.play_button.SetBitmap(self.pause_bitmap)
45544587
else:
45554588
wx.MessageBox(_("Unable to load %s: Unsupported format?") % path,
45564589
_("Error"), wx.ICON_ERROR | wx.OK)
@@ -4561,21 +4594,28 @@ def play():
45614594
# time.sleep(0.3) # 1.3.6.4 [JWDJ] on Mac the first note is skipped the first time. hope this helps
45624595
# self.mc.Seek(self.play_start_offset, wx.FromStart)
45634596
self.play_button.SetBitmap(self.pause_bitmap)
4564-
self.progress_slider.SetRange(0, self.mc.Length())
4597+
self.progress_slider.SetRange(0, int(self.mc.Length())) #FAU:MIDIPLAY: mplay might return a float. thus forcing an int
45654598
self.progress_slider.SetValue(0)
45664599
self.OnBpmSlider(None)
45674600
self.update_playback_rate()
4568-
if wx.Platform == "__WXMAC__":
4569-
self.mc.Seek(0) # When using wx.media.MEDIABACKEND_QUICKTIME the music starts playing too early (when loading a file)
4570-
time.sleep(0.5) # hopefully this fixes the first notes not being played
4601+
#FAU:MIDIPLAY: The next 'if' was when using MediaCtrl which is not used anymore. Todo: remove the corresponding code if confirmed
4602+
#if wx.Platform == "__WXMAC__":
4603+
# self.mc.Seek(0) # When using wx.media.MEDIABACKEND_QUICKTIME the music starts playing too early (when loading a file)
4604+
# time.sleep(0.5) # hopefully this fixes the first notes not being played
45714605
self.play()
45724606
wx.CallAfter(play)
45734607

45744608
def OnAfterStop(self):
4609+
self.set_loop_midi_playback(False)
45754610
# 1.3.6.3 [SS] 2015-05-04
45764611
self.stop_playing()
4577-
self.reset_BpmSlider()
4578-
self.flip_tempobox(False)
4612+
#FAU preserve latest bpm choice
4613+
#self.reset_BpmSlider()
4614+
#FAU20250125: Do not hide it if supported
4615+
if self.settings['midiplayer_path']:
4616+
self.flip_tempobox(False)
4617+
if wx.Platform != "__WXMSW__":
4618+
self.toolbar.Realize() # 1.3.6.4 [JWDJ] fixes toolbar repaint bug for Windows
45794619

45804620
def OnToolRecord(self, evt):
45814621
if self.record_thread and self.record_thread.is_running:
@@ -4594,19 +4634,21 @@ def OnToolRecord(self, evt):
45944634
self.record_thread.start()
45954635

45964636
def OnToolStop(self, evt):
4597-
self.set_loop_midi_playback(False)
4598-
self.stop_playing()
4637+
#FAU 20250125: Cleaning, trying to centralised what is common to Stop avoiding of mon to Stop instead of multiple call
4638+
self.OnAfterStop()
4639+
#self.set_loop_midi_playback(False)
4640+
#self.stop_playing()
45994641
# 1.3.6.3 [SS] 2015-04-03
46004642
#self.play_panel.Show(False)
4601-
self.flip_tempobox(False)
4602-
self.progress_slider.SetValue(0)
4643+
#self.flip_tempobox(False)
4644+
#self.progress_slider.SetValue(0)
46034645
# self.reset_BpmSlider() #[EPO] 2018-11-20 make sticky - this is new functionality
4604-
if wx.Platform != "__WXMSW__":
4605-
self.toolbar.Realize() # 1.3.6.4 [JWDJ] fixes toolbar repaint bug for Windows
4646+
#if wx.Platform != "__WXMSW__":
4647+
# self.toolbar.Realize() # 1.3.6.4 [JWDJ] fixes toolbar repaint bug for Windows
46064648
if self.record_thread and self.record_thread.is_running:
46074649
self.OnToolRecord(None)
4608-
if self.uses_fluidsynth:
4609-
self.OnAfterStop()
4650+
#if self.uses_fluidsynth:
4651+
# self.OnAfterStop()
46104652

46114653
def OnSeek(self, evt):
46124654
self.mc.Seek(self.progress_slider.GetValue())
@@ -4629,21 +4671,31 @@ def OnPlayTimer(self, evt):
46294671
if not self.is_closed:
46304672
if self.mc.is_playing:
46314673
self.started_playing = True
4632-
4674+
4675+
if wx.Platform == "__WXMAC__": #FAU:MIDIPLAY: Used to give the hand to MIDI player
4676+
delta = self.mc.IdlePlay()
4677+
#print(self.mc.get_songinfo)
4678+
if delta == 0:
4679+
if self.loop_midi_playback:
4680+
self.mc.Seek(0)
4681+
else:
4682+
self.mc.is_play_started = False
4683+
46334684
offset = self.mc.Tell()
46344685
if offset >= self.progress_slider.Max:
46354686
length = self.mc.Length()
4636-
self.progress_slider.SetRange(0, length)
4637-
4687+
self.progress_slider.SetRange(0, int(length)) #FAU:MIDIPLAY: mplay might return a float. thus forcing an int
4688+
46384689
if self.settings.get('follow_score', False):
46394690
self.queue_number_follow_score += 1
46404691
queue_number = self.queue_number_follow_score
4641-
wx.CallLater(1, self.FollowScore, offset, queue_number) #[EPO] 2018-11-20 first arg 0 causes exception
4642-
4692+
#wx.CallLater(1, self.FollowScore, offset, queue_number) #[EPO] 2018-11-20 first arg 0 causes exception
4693+
self.FollowScore(offset, queue_number)
4694+
46434695
self.progress_slider.SetValue(offset)
4644-
elif self.started_playing and self.uses_fluidsynth and not self.mc.is_paused:
4696+
elif self.started_playing and not self.mc.is_paused: #and self.uses_fluidsynth
46454697
self.started_playing = False
4646-
self.OnToolStop(None)
4698+
wx.CallLater(500, self.OnAfterStop)
46474699

46484700
def FollowScore(self, offset, queue_number):
46494701
if self.queue_number_follow_score != queue_number:
@@ -7487,7 +7539,15 @@ def extract_note_timings(self, midi_tune, svg_tune):
74877539
midi_rows = [i + 1 for i in midi_rows]
74887540

74897541
errors = defaultdict(lambda: defaultdict(int))
7490-
pos_re = re.compile(r'^\s*(\d+\.\d+)\s+CntlParm\s+1\s+unknown\s+=\s+(\d+)')
7542+
#FAU: jwdj/EasyABC#99 Starting from commit sshlien/abcmidi@705d9e1f737a2db9fdc615b622bc75204b1bcbee of midi2abc, Follow_score not working
7543+
#FAU: This commit of midi2abc changed the format of CntlParm.
7544+
#FAU: it used to be printf("CntlParm %2d %s = %d\n",chan+1, ctype[control],value);
7545+
#FAU: it is now printf("CntlParm %2d %s = %d %d\n",chan+1, ctype[control],control,value);
7546+
#FAU: Following regex is expecting only one decimal however an extra one is now present
7547+
#FAU: To have a regex working for both version, \s*\d* is added
7548+
#FAU: might need some further check
7549+
#pos_re = re.compile(r'^\s*(\d+\.\d+)\s+CntlParm\s+1\s+unknown\s+=\s+(\d+)')
7550+
pos_re = re.compile(r'^\s*(\d+\.\d+)\s+CntlParm\s+1\s+unknown\s+=\s*\d*\s+(\d+)')
74917551
note_re = re.compile(r'^\s*(\d+\.\d+)\s+Note (on|off)\s+(\d+)\s+(\d+)')
74927552
tempo_re = re.compile(r'^\s*(\d+\.\d+)\s+Metatext\s+tempo\s+=\s+(\d+\.\d+)\s+bpm')
74937553
new_track_re = re.compile(r'^Track \d+ contains')
@@ -8575,7 +8635,8 @@ class AboutFrame(wx.Dialog):
85758635
</center>
85768636
<p><b>{0}</b><br/>
85778637
an open source ABC editor for Windows, OSX and Linux. It is published under the <a href="https://www.gnu.org/licenses/gpl-2.0.html">GNU Public License</a>. </p>
8578-
<p><center><a href="https://www.nilsliberg.se/ksp/easyabc/">https://www.nilsliberg.se/ksp/easyabc/</a></center></p>
8638+
<p><center>initial repository was at <a href="https://www.nilsliberg.se/ksp/easyabc/">https://www.nilsliberg.se/ksp/easyabc/</a></center></p>
8639+
<p><center>Now documentation available here<a href="https://easyabc.sourceforge.net">https://easyabc.sourceforge.net</a></center></p>
85798640
<p><u>Features</u>:</p>
85808641
<ul style="line-height: 150%; margin-top: 3px;">
85818642
<li> Good ABC standard coverage thanks to internal use of abcm2ps and abc2midi
@@ -8599,6 +8660,7 @@ class AboutFrame(wx.Dialog):
85998660
</ul>
86008661
86018662
<p><b>EasyABC</b> is brought to you by <b>Nils Liberg</b>, Copyright &copy; 2010-2012.</p>
8663+
<p><b>EasyABC</b> is maintained by <b>Jan Wybren de Jong</b>, <b>Seymour Shlien</b> and by <b>Fr&eacute;d&eacute;ric Aup&eacute;pin</b> for Mac adaptation</p>
86028664
<p><b>Credits</b> - software components used by EasyABC:</p>
86038665
<ul class="nicelist">
86048666
<li><a href="http://moinejf.free.fr/">abcm2ps</a> for converting ABC code to note images (developed/maintained by Jean-Fran&ccedil;ois Moine)</li>
@@ -8610,9 +8672,10 @@ class AboutFrame(wx.Dialog):
86108672
<li><a href="https://www.mxm.dk/products/public/pythonmidi">python midi package</a> for the initial parsing of midi files to be imported</li>
86118673
<li><a href="https://www.pygame.org/download.shtml">pygame</a> (which wraps <a href="https://sourceforge.net/apps/trac/portmedia/wiki/portmidi">portmidi</a>) for real-time midi input</li>
86128674
<li><a href="https://www.fluidsynth.org/">FluidSynth</a> for playing midi (and made fit for Python by <a href="https://wim.vree.org/svgParse/index.html">Willem Vree</a>)</li>
8675+
<li><a href="https://github.com/jheinen/mplay">Python MIDI Player</a> for playing midi on Mac</li>
86138676
<li>Thanks to Guido Gonzato for providing the fields and command reference.
86148677
<li><br>Many thanks to the translators: Valerio&nbsp;Pelliccioni, Guido&nbsp;Gonzato&nbsp;(italian), Bendix&nbsp;R&oslash;dgaard&nbsp;(danish), Fr&eacute;d&eacute;ric&nbsp;Aup&eacute;pin&nbsp;(french), Bernard&nbsp;Weichel&nbsp;(german), Jan&nbsp;Wybren&nbsp;de&nbsp;Jong&nbsp;(dutch) and Wu&nbsp;Xiaotian&nbsp;(chinese).</li>
8615-
<li>Universal binaries of abcm2ps and abc2midi for OSX are available thanks to Chuck&nbsp;Boody.</li>
8678+
<li>Universal binaries of <a href="https://abcplus.sourceforge.net/#abcm2ps">abcm2ps</a> and <a href="https://abcplus.sourceforge.net/#abcmidi">abc2midi</a> for OSX are available thanks to Chuck&nbsp;Boody and Guido Gonzato</li>
86168679
</ul>
86178680
86188681
<p><b>Links</b></p>
@@ -8621,7 +8684,7 @@ class AboutFrame(wx.Dialog):
86218684
<li><a href="http://abcplus.sourceforge.net/">abcplus.sourceforge.net</a></li>
86228685
<li><a href="http://moinejf.free.fr/">Jef Moine's abcm2ps page</a></li>
86238686
<li><a href="https://abcmidi.sourceforge.io/">Seymour Shlien's abcMIDI page</a></li>
8624-
<li><a href="http://www.folkwiki.se/">folkwiki.se - Swedish folk music</a> (my involvement here is the reason why I implemented the program)</li>
8687+
<li><a href="http://www.folkwiki.se/">folkwiki.se - Swedish folk music</a> (initial involvement of Nils here is the reason why he implemented the program)</li>
86258688
</ul>
86268689
</body>
86278690
</html>

0 commit comments

Comments
 (0)