September 20, 2021, 08:19:08

Author Topic: My Music Editor  (Read 5642 times)

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 736
  • nothing is personal
Re: My Music Editor
« Reply #30 on: June 06, 2021, 21:58:14 »
So midi master.. according to what I see.. all the notes that are overlapping each other turn into a Bemol Sign
On the BB Chord Case they are not overlapping each other , so why do i need to use Bemol.

anyway.. dont think i understood the note tables you posted..

that's why i postponed it for later.

anyway.. Now im starting to implement some things.. than ill post a picture and see what you think
...

Offline Midimaster

  • Sr. Member
  • ****
  • Posts: 363
    • Midimaster Music Education Software
Re: My Music Editor
« Reply #31 on: June 06, 2021, 23:59:57 »
I may look like you found the rule for b or #. But the example of the Bb-chord already shows you, that this cannot be the rule.

As I said, there are 12 tables which define, when or whether a midi note is displayed as with a # or a b sign.

This what I call "translation table". At the moment you try to use the midi-number to find the notation position. But the correct way is to first "translate" the midi-number into a notation-number. then you will find the correct position.

For chords this way is a 100% working solution.

1.step: Calculate
Code: [Select]
MidiMod%=(midinumber mod 12)
Octave%=(midinumber/12)

2.step: Now use one of the 12 tables to get the NotationMod:
Code: [Select]
NotationMod%= Table[TableNumber%, MidiMod]
NotationPos%=NotationMod*Octave
now you now the vertical pos of the note in the score


3.step
the system can give you additional informations now:

Code: [Select]
Select (NotationMod mod 3)
    Case 0
        ' note needs a b sign
    Case 1
        ' note needs no sign
    Case 2
        ' note needs a # sign
end select

The only question that remains is: "Which table do I use?"

The answer is: "depends on...!". In the case of chord this question is easy, because you only have to find the table which contains all three midinumbers of your chord.

In 12 hours I will send you the 12 tables and a demo code. (now it is round midnight)
See my current project on PlayStore: 20Tracks-Audio-Player https://play.google.com/store/apps/details?id=midimaster.twentytrackd

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 736
  • nothing is personal
Re: My Music Editor
« Reply #32 on: June 07, 2021, 03:43:26 »
Awesome.. Ill wait for the demo..

I told you im gonna listen to you eventually lol :)
...

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 736
  • nothing is personal
Re: My Music Editor
« Reply #33 on: June 07, 2021, 05:03:49 »
Progress Report..

Now I got 4 Lines Notes Ladder Editing.
Up till now it was only one Line Note Editing



Making this a true professional any note sheet notation Editor.. well thats too much for me for the moment..
Ill just make this work right and ill be pleased
...

Offline Midimaster

  • Sr. Member
  • ****
  • Posts: 363
    • Midimaster Music Education Software
Re: My Music Editor
« Reply #34 on: June 07, 2021, 15:36:33 »
Ok, here is the demo for the 12->21 converter. This enables to write the chords automatically correct.

You can use some of the fundamental  functions:
Code: BlitzMax
  1. Function EasyTranslate:Int[] ( MidiChord:Int[] )
  2.         ' converts a midi noted chord into a notation noted chord
  3.         ' the array can contain 1 to 4 notes
  4.  
  5.  
  6. Function Name$(Note%)
  7.         ' returns the name of a notation note
  8.         ' notemod    0   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21
  9.         ' --> name  Cb   C  C#  Db   D  D#  Eb   E  E#  Fb   F  F#  Gb   G  G#  Ab   A  A#  Bb   B  B#
  10.  
  11.  
  12. Function DrawNotes (Chord:Int[])
  13.                 'converts a notation chord into dispayed notes
  14.                 Local ZeroY%=300, Distance%=10, BassDistance%=25
  15.                 ' flexible in scaling:
  16.                 ' ZeroY defines the absolute Y-position of  both systems
  17.                 ' Distance defines the absolute y-diff from one note to the next higher note
  18.                 ' BassDistance defines the relative distance of bass system to treble system
  19.                
  20.  
  21. Function PaintHelpingLines(X%, Note%, Clef%=TREBLE, ZeroY%, Distance%, BassDistance%)
  22.                 'paints all necessary helplines of a notation note
  23.  
  24.  
  25. Function NoteToMidi:Int(Note%)
  26.         ' converts a notation note back to a midi note
  27.         ' notemod      0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20        
  28.         ' --> to midi -1   0   1   1   2   3   3   4   5   4   5   6   6   7   8   8   9  10  10  11  12
  29.  


You can add your chords for testing here:
Code: BlitzMax
  1. Function NewChord()
  2.         number=number +1
  3.         Select Number
  4.                 Case 1
  5.                         chord=[58,62,65]    'Bb
  6.                 Case 2
  7.                         ...
  8.                 Case 9
  9.                         chord=[57,60,64]    'Am
  10.                 Case 10
  11.                         chord=....
  12.  
  13.  




The whole runnable example


Start the app and click with the mouse to check some chords....

Code: BlitzMax
  1. Graphics 600,600
  2. SetBlend alphablend
  3. Notation.StartUp
  4.  
  5.  
  6. Global MidiChord%[]=[60,63,67]    'Am
  7.  
  8. Global  ShowChord:Int[]=Notation.EasyTranslate(MidiChord)
  9. Global Number
  10. Notation.ChordInfo(MidiChord, ShowChord)
  11.  
  12. SetClsColor 255,255,255
  13. Repeat
  14.         Cls
  15.         Notation.DrawNotes Showchord
  16.         If MouseHit(1)
  17.                 NewChord
  18.         EndIf
  19.         Flip 1
  20. Until AppTerminate()
  21.  
  22.  
  23.  
  24. Function NewChord()
  25.         number=number +1
  26.                         Midichord=[58+number,59+number,60+number]    'Bb
  27.  
  28.         ShowChord = Notation.EasyTranslate(MidiChord)
  29.         Notation.ChordInfo(MidiChord, ShowChord)       
  30. End Function
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44. Type Notation
  45.         Global MidiTable:Int[]= [-1,0,1, 1,2,3, 3,4,5 ,4,5,6, 6,7,8,  8,9,10,  10,11,0]
  46.         Global Names:String[]= "Cb,C,C#,Db,D,D#,Eb,E,E#,Fb,F,F#,Gb,G,G#,Ab,A,A#,Bb,B,B#".split(",")
  47.     Global NoteImages:TImage
  48.         Global TableMidi:Int[15,7], TableNote:Int[15,7]
  49.  
  50.  
  51.  
  52.         Function StartUp()
  53.                 'builds the 13 tables from this 2 "exotic" strings
  54.                 Local t1$="0|2|4|5|7|9|11|0|2|4|6|7|9|11|0|2|4|5|7|9|10|1|2|4|6|7|9|11|0|2|3|5|7|9|10|1|2|4|6|8|9|11|0|2|3|5|7|8|10|1|3|4|6|8|9|11|0|1|3|5|7|8|10|1|3|4|6|8|10|11|0|1|3|5|6|8|10|11|1|3|5|6|8|10|1|3|5|6|8|10|11|"
  55.                 Local t2$="1|4|7|10|13|16|19|1|4|7|11|13|16|19|1|4|7|10|13|16|18|2|4|7|11|13|16|19|1|4|6|10|13|16|18|2|4|7|11|14|16|19|1|4|6|10|13|15|18|2|5|7|11|14|16|19|1|3|6|10|13|15|18|2|5|7|11|14|17|19|1|3|6|10|12|15|18|21|3|6|10|12|15|18|2|5|8|11|14|17|19|"
  56.                 t1=t1 + "1|3|5|6|8|10|0|1|3|4|6|8|10|11|"
  57.                 t2=t2 + "2|5|8|11|14|17|-1|3|6|9|12|15|18|21|"
  58.  
  59. 'cis h#    1| 3| 5| 6| 8|10| 0|
  60. '14.       2| 5| 8|11|14|17|-1|
  61.  
  62. 'Cb  fb    1| 3| 4| 6| 8|10|11|
  63. '13.       3| 6| 9|12|15|18|21|
  64.                
  65.                 Local v1$[]=t1.split("|")
  66.                 Local v2$[]=t2.split("|")
  67.                 For Local I%=0 To 14
  68.                         For Local j%=0 To 6
  69.                                 TableMidi[i,j]=v1[i*7+j].toint()
  70.                                 TableNote[i,j]=v2[i*7+j].toint()
  71.                         Next
  72.                 Next
  73.                 'ShowTable
  74.                 ' load some note images for testing:
  75.                 NoteImages=LoadAnimImage("noten.png",60, 140,0,15)
  76.         End Function
  77.  
  78.  
  79.  
  80.         Function ShowTable()
  81.                 ' shows all 13 tables for debugging purposes only:
  82.                         For Local I%=0 To 14
  83.                                 Print "------------Table Nr " + (i+1) + "--------------------"
  84.                                 Local a$= "", b$= ""
  85.                                 For Local j%=0 To 6
  86.                                         a=a+ " " + TableMidi[i,j]
  87.                                         b=b+ " " + TableNote[i,j]
  88.                                 Next
  89.                                 Print a
  90.                                 Print b
  91.                         Next
  92.         End Function
  93.  
  94.  
  95.        
  96.         Function NoteToMidi:Int(Note%)
  97.                 ' converts a notation note back to a midi note
  98.                 ' notemod      0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20        
  99.         ' --> to midi -1   0   1   1   2   3   3   4   5   4   5   6   6   7   8   8   9  10  10  11  12
  100.                 Local Octave:Int=note/21
  101.                 Local NoteMod:Int=Note Mod 21
  102.                 Local Midi:Int=MidiTable[NoteMod] + 12*Octave
  103.                 Print Note + " " + Names[NoteMod] + " => midi " + (Midi)
  104.                 Return midi
  105.         End Function
  106.        
  107.  
  108.  
  109.  
  110.         Function EasyTranslate:Int[] (MidiChord:Int[])
  111.                 ' converts a midi noted chord into a notation noted chord
  112.                 ' the array can contain 1 to 4 notes
  113.                 Local TakeTable%=Notation.WhichTable(MidiChord)
  114.                 Print "Chord found in table " + TakeTable
  115.                 Return Translate(TakeTable,MidiChord)  
  116.         End Function
  117.  
  118.  
  119.  
  120.  
  121.        
  122.         Function WhichTable:Int(MidiChord:Int[])
  123.                 'trys to find out which of the 13 tables is the best
  124.                 'returns a number between 0 and 12
  125.                 Local Result%
  126.                 For Local i:Int=0 To 12
  127.                         Result= CheckTable(i , MidiChord)
  128.                         If Result=True Then Return i
  129.                 Next
  130.                 Return -1
  131.         End Function
  132.        
  133.        
  134.        
  135.        
  136.         Function CheckTable:Int(Nr%, MidiChord:Int[])
  137.                 'checks whether all notes of a chord are member of this table
  138.                 For Local i:Int=0 To MidiChord.Length-1
  139.                         Local SearchNote% = MidiChord[i] Mod 12
  140.                         Local Result%=False
  141.                         For Local j%=0 To 6
  142.                                 If TableMidi[Nr,j] = SearchNote
  143.                                         Result=True
  144.                                         Exit
  145.                                 EndIf
  146.                         Next
  147.                         If Result=False Return False
  148.                 Next
  149.                 Return True
  150.         End Function
  151.        
  152.        
  153.         Function Translate:Int[] (Nr%, MidiChord:Int[])
  154.                 ' converts a midi noted chord into a notation noted chord
  155.                 ' the array can contain 1 to 4 notes
  156.                 Local ReturnChord:Int[MidiChord.Length]
  157.                 If Nr=-1
  158.                         ' no real chord! use as minimum same sign
  159.                         Return UseAllSameSign(MidiChord)
  160.                        
  161.                        
  162.                 EndIf
  163.                 For Local i:Int=0 To MidiChord.Length-1
  164.                         Local SearchNote% = MidiChord[i] Mod 12
  165.                         Local Octave%=MidiChord[i] / 12
  166.                         For Local j%=0 To 6
  167.                                 If TableMidi[Nr,j] = SearchNote
  168.                                         'Print "found at " + j
  169.                                         ReturnChord[i]= TableNote[Nr,j] +21*Octave
  170.                                         Exit
  171.                                 EndIf
  172.                         Next
  173.                 Next
  174.                 Return ReturnChord
  175.         End Function    
  176.        
  177.  
  178.  
  179.  
  180.         Const FLAT:Int=0, SHARP:Int=1
  181.        
  182.         Function UseAllSameSign:Int[] (MidiChord:Int[], Iteration:Int=0)
  183.                 ' tricky new function to process also "strange chords"
  184.                 ' if all 14 tables fail this algo trys to prevent notes on the same line
  185.                 Local SameTableNote[][]= New Int[][4]
  186.                 '                  [C   D   E  F     G     A     B]
  187.                 SameTableNote[0]=  [1,3,4,6,7,10,12,13,15,16,18,19]
  188.                 SameTableNote[1]=  [1,2,4,5,7,10,11,13,14,16,17,19]
  189.                 SameTableNote[2]=  [1,3,4,6,9,10,12,13,15,16,18,21]
  190.                 SameTableNote[3]=  [-1,2,4,5,7,8,11,13,14,16,17,19]
  191.  
  192.                 Local ReturnChord:Int[MidiChord.Length]
  193.                
  194.                 Print "STRANGE CHORD! now Using UseAllSameSign() function with Iteration-Round=" + Iteration
  195.                 ' first use one of the tables:
  196.                 For Local i:Int=0 To MidiChord.Length-1
  197.                         Local SearchNote% = MidiChord[i] Mod 12
  198.                         Local Octave%=MidiChord[i] / 12
  199.                         ReturnChord[i]= SameTableNote[Iteration][SearchNote] +21*Octave
  200.                 Next
  201.                
  202.                 'now test, whether this table also produce notes on the same line:
  203.                         For Local i:Int=0 To MidiChord.Length-1
  204.                                 For Local j:Int=i+1 To MidiChord.Length-1              
  205.                                         If YPos(ReturnChord[i]) = YPos(ReturnChord[j])
  206.                                                 'If yes... try the other table
  207.                                                 If Iteration < 3 'for not producing a endless loop
  208.                                                         Return UseAllSameSign(MidiChord,Iteration+1)
  209.                                                 Else
  210.                                                         Print "Needs Mix Methode"
  211.                                                         Return UseMixedSigns (MidiChord, ReturnChord)
  212.                                                 EndIf
  213.                                         EndIf
  214.                                 Next
  215.                         Next
  216.                 Return ReturnChord     
  217.         End Function
  218.        
  219.        
  220.         Function UseMixedSigns:Int[] (MidiChord:Int[], BadChord:Int[])
  221.                 ' ultimate chance for chords: Try to mix # with b or send BadChord
  222.                 Local list:TList=New TList
  223.                 Local SearchNote% = MidiChord[0] Mod 12
  224.                 Local Octave%=MidiChord[0] / 12
  225.                 Local locChord:Int[]
  226.                 AddChordsToListe(List, locChord, SearchNote, Octave)
  227.                        
  228.                 For Local i:Int=1 To MidiChord.Length-1
  229.                         Local SearchNote% = MidiChord[i] Mod 12
  230.                         Local Octave%=MidiChord[i] / 12
  231.                
  232.                         For Local Chord:Int[]=EachIn list
  233.                                 If chord.length=i
  234.                                         AddChordsToListe(List, Chord, SearchNote, Octave)
  235.                                         List.Remove Chord
  236.                                 EndIf
  237.                         Next
  238.                 Next
  239.                 Print "EXTREM STRANGE CHORD! now Using UseMixedSigns() function"
  240.                 For Local Chord:Int[]=EachIn list
  241.                         Return chord
  242.                 Next
  243.                 Print "!!!!! BAD CHORD! no solution found !!!!"
  244.                 Return BadChord        
  245.         End Function
  246.  
  247.  
  248.         Function AddChordsToListe(List:TList, Chord[], SearchNote, Octave)
  249.                 Print "Adding " + Searchnote
  250.                 Local last%=Chord.length
  251.                 Local NewChord_I:Int[last+1]
  252.                 Local NewChord_II:Int[last+1]
  253.                 For Local i%=0 To last-1
  254.                         NewChord_I [i] = Chord[i]
  255.                         NewChord_II[i] = Chord[i]
  256.                 Next
  257.                         Select SearchNote
  258.                                 Case 0 
  259.                                         NewChord_I[last]=-1+21*Octave  
  260.                                         NewChord_II[last]=1+21*Octave  
  261.                                 Case 1
  262.                                         NewChord_I[last]=2+21*Octave
  263.                                         NewChord_II[last]=3+21*Octave
  264.                                 Case 2
  265.                                         NewChord_I[last]=4+21*Octave
  266.                                 Case 3
  267.                                         NewChord_I[last]=5+21*Octave
  268.                                         NewChord_II[last]=6+21*Octave          
  269.                                 Case 4
  270.                                         NewChord_I[last]=7+21*Octave
  271.                                         NewChord_II[last]=9+21*Octave                                          
  272.                                 Case 5
  273.                                         NewChord_I[last]=8+21*Octave
  274.                                         NewChord_II[last]=10+21*Octave                                         
  275.                                 Case 6
  276.                                         NewChord_I[last]=11+21*Octave
  277.                                         NewChord_II[last]=12+21*Octave                                                                         
  278.                                 Case 7
  279.                                         NewChord_I[last]=13+21*Octave
  280.                                 Case 8
  281.                                         NewChord_I[last]=14+21*Octave
  282.                                         NewChord_II[last]=15+21*Octave
  283.                                 Case 9
  284.                                         NewChord_I[last]=16+21*Octave                  
  285.                                 Case 10
  286.                                         NewChord_I[last]=17+21*Octave
  287.                                         NewChord_II[last]=18+21*Octave         
  288.                                 Case 11
  289.                                         NewChord_I[last]=19+21*Octave
  290.                                         NewChord_II[last]=21+21*Octave
  291.                         EndSelect
  292.                 If ContainsSameLine(NewChord_I)=False
  293.                         Print "ADD **** Chord_I to list" + StringFromChord(newchord_I)
  294.                         List.Addlast NewChord_I
  295.                 EndIf
  296.                
  297.                 If NewChord_II[Last]>0
  298.                         If ContainsSameLine(NewChord_II)=False
  299.                                 List.AddLast NewChord_II
  300.                                 Print "ADD **** Chord_II to list" + StringFromChord(newchord_II)
  301.                         EndIf
  302.                 EndIf
  303.         End Function
  304.  
  305.  
  306. Function ContainsSameLine:Int(Chord:Int[])
  307.         For Local i:Int=0 To Chord.Length-1
  308.                 For Local j:Int=i+1 To Chord.Length-1          
  309.                         If YPos(Chord[i]) = YPos(Chord[j])
  310.                                 Return True
  311.                         EndIf
  312.                 Next
  313.         Next
  314.         Return False
  315. End Function
  316.  
  317. Function StringFromChord$(Chord:Int[])
  318.         Local s$
  319.         For Local i%=0 To chord.length-1
  320.                 s=s + chord[i] + "-"
  321.         Next
  322.         Return s
  323. EndFunction
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.        
  334.         Function Name$(Note%)
  335.                 ' returns the name of a notation note
  336.                 ' notemod    0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20
  337.                 ' --> name  Cb   C  C#  Db   D  D#  Eb   E  E#  Fb   F  F#  Gb   G  G#  Ab   A  A#  Bb   B  B#
  338.                 Return Names[note Mod 21]
  339.         End Function
  340.        
  341.        
  342.         Const TREBLE:Int=0, BASS:Int=1
  343.        
  344.         Function YPos:Int(note%, Clef%=TREBLE)
  345.                 'returns the relative screen-y position of a notation note             
  346.                 Local pos:Int
  347.                 If clef=TREBLE
  348.                         Return Int(note/3) -28
  349.                 EndIf
  350.                 Return Int(note/3) -16
  351.         End Function
  352.        
  353.  
  354.         Function NeedsHelpingLines:Int (Note%, Clef%=TREBLE)
  355.                 ' finds out whether this note needs helplines
  356.                 Local pos:Int=Ypos(note,Clef)
  357.                 If pos<8 Or pos>18
  358.                         Return True
  359.                 EndIf
  360.                 Return False
  361.         End Function
  362.        
  363.        
  364.         Function PaintHelpingLines(X%, Note%, Clef%=TREBLE, ZeroY%, Distance%, BassDistance%)
  365.                 'paints helplines of a note
  366.                 If NeedsHelpingLines(Note, Clef)=False Return
  367.                 Local pos:Int=Ypos(note,Clef)
  368.                 BassDistance=BassDistance*Clef
  369.                 SetColor 1,1,1
  370.                 If pos<8
  371.                         For Local i%=7 To pos Step -2
  372.                                 DrawRect X-8,ZeroY-((i-Bassdistance)*distance),40,1
  373.                         Next  
  374.                 Else
  375.                         For Local i%=19 To pos Step 2
  376.                                 DrawRect x-8,ZeroY-((i-Bassdistance)*distance),40,1
  377.                         Next  
  378.                 EndIf
  379.                 SetColor 255,255,255
  380.         End Function  
  381.  
  382.         Function DrawNotes (Chord:Int[])
  383.                 'converts a notation chord into dispayed notes
  384.                 Local ZeroY%=300, Distance%=10, BassDistance%=25, Imagedistance%=70
  385.                 ' flexible in scaling:
  386.                 ' ZeroY defines the absolute Y-position of  both systems
  387.                 ' Distance defines the absolute y-diff from one note to the next higher note
  388.                 ' BassDistance defines the relative distance of bass system to treble system
  389.                 ' ImageDistance is related to the "noten.png" (fine adjusting)
  390.                 ' this "noten.png" is best for distances from 8 to 11
  391.                
  392.                 '5 score-lines in bass and treble
  393.                 SetColor 1,1,1
  394.                 DrawText "Midi : " + MidiChord[0]+ "-" +  + MidiChord[1]+ "-" + MidiChord[2],100,100
  395.                 For Local i%=0 To 4
  396.                         DrawRect 100,ZeroY-((i*2+9)*distance),400,1
  397.                         DrawRect 100,ZeroY-((i*2+9-BassDistance)*distance),400,1
  398.                 Next
  399.                 SetColor 255,255,255
  400.                
  401.                 'the keys:
  402.                 DrawImage NoteImages,120,ZeroY-12*Distance-ImageDistance,0
  403.                 DrawImage NoteImages,120,ZeroY-(12-Bassdistance)*Distance-ImageDistance,1
  404.  
  405.                 ' paint the chord
  406.                 Local signCounter%=0
  407.                 For Local i:Int=0 To Chord.Length-1
  408.                         'Print "found chord note " + Chord[i] + " " + ypos(chord[i])
  409.                         PaintHelpingLines(250+i*25, Chord[i], 0, ZeroY, Distance, BassDistance)
  410.                         Select Chord[i] Mod 3
  411.                                 Case 0
  412.                                         DrawImage NoteImages,220+signCounter,ZeroY- ypos(Chord[i])*Distance-ImageDistance,10                                           
  413.                                         signCounter=signCounter+15
  414.                                 Case 2
  415.                                         DrawImage NoteImages,220+signCounter,ZeroY- ypos(Chord[i])*Distance-ImageDistance,9                                            
  416.                                         signCounter=signCounter+15
  417.                         End Select
  418.                         DrawImage NoteImages,250+i*25,ZeroY- ypos(Chord[i])*Distance-ImageDistance,5                   
  419.                 Next
  420.                
  421.                
  422.                 'paint it in bass system too
  423.                 Local AsBass%=1
  424.                 signCounter=0
  425.                 For Local i:Int=0 To Chord.Length-1
  426.                         'Print "found chor note " + Chord[i] + " " + ypos(chord[i])
  427.                         PaintHelpingLines(350+i*25, Chord[i], AsBass, ZeroY, Distance, BassDistance)
  428.                         Select Chord[i] Mod 3
  429.                                 Case 0
  430.                                         DrawImage NoteImages,320+signCounter,ZeroY- (ypos(Chord[i],AsBass)-BassDistance)*Distance-ImageDistance,10                                             
  431.                                         signCounter=signCounter+15
  432.                                 Case 2
  433.                                         DrawImage NoteImages,320+signCounter,ZeroY- (ypos(Chord[i],AsBass)-BassDistance)*Distance-ImageDistance,9                                              
  434.                                         signCounter=signCounter+15
  435.                         End Select
  436.                         DrawImage NoteImages,350+i*25,ZeroY- (ypos(Chord[i],AsBass)-BassDistance)*Distance-ImageDistance,6                     
  437.                 Next
  438.         End Function
  439.  
  440.  
  441.         Function ChordInfo(Chord:Int[],ShowChord:Int[])
  442.                 Print "************************************"
  443.                 Print "S C A N   R E S U L T S:"
  444.                 Local ChordInfo$ = "      Midi-Chord was: "
  445.                 Local NoteInfo$  = "       Note-Chord is: "
  446.                 Local NameInfo$  = "           Names are: "
  447.                 Local TrebleInfo$= "Draw at treble lines: "
  448.                 Local BassInfo$  = " Draw at bass lines : "
  449.                 For Local I%=0 To Chord.length-1
  450.                         ChordInfo= ChordInfo + + Chord[i]  + " "
  451.                         NoteInfo= NoteInfo + ShowChord[i] + " "
  452.                         NameInfo= NameInfo + Notation.name(ShowChord[i]) + " "
  453.                         TrebleInfo= TrebleInfo + Notation.Ypos(ShowChord[i]) + " "
  454.                         BassInfo= BassInfo + Notation.Ypos(ShowChord[i],1) + " "
  455.                 Next
  456.                 Print ChordInfo
  457.                 Print NoteInfo
  458.                 Print NameInfo
  459.                 Print TrebleInfo
  460.                 Print BassInfo
  461.         End Function
  462.  
  463. End Type
  464.  
  465. Rem
  466. Table-Explanation:
  467. -----------------------------------
  468. Scale      New       Midi-Notes
  469. Order      sign      Notation-notes
  470. -----------------------------------
  471.  
  472. -----------------------------------
  473. no sign
  474. Table     C  D  E  F  G  A  B
  475. -----------------------------------
  476. C         0| 2| 4| 5| 7| 9|11|
  477. 0.        1| 4| 7|10|13|16|19|
  478. -----------------------------------
  479. all #
  480. Tables    C  D  E  F  G  A  B
  481. -----------------------------------
  482. G   f#    0| 2| 4| 6| 7| 9|11|
  483. 1.        1| 4| 7|11|13|16|19|
  484. -----------------------------------
  485. D   c#    1| 2| 4| 6| 7| 9|11|
  486. 3.        2| 4| 7|11|13|16|19|
  487. -----------------------------------
  488. A   g#    1| 2| 4| 6| 8| 9|11|
  489. 5.        2| 4| 7|11|14|16|19|
  490. -----------------------------------
  491. E   d#    1| 3| 4| 6| 8| 9|11|
  492. 7.        2| 5| 7|11|14|16|19|
  493. -----------------------------------
  494. H   a#    1| 3| 4| 6| 8|10|11|
  495. 9.        2| 5| 7|11|14|17|19|
  496. -----------------------------------
  497. fis e#    1| 3| 5| 6| 8|10|11|
  498. 12.       2| 5| 8|11|14|17|19|
  499. -----------------------------------
  500. cis h#    1| 3| 5| 6| 8|10| 0|
  501. 14.       2| 5| 8|11|14|17|-1|
  502. -----------------------------------
  503. -----------------------------------
  504. all b
  505. Tables    C  D  E  F  G  A  B
  506. -----------------------------------
  507. F   hb    0| 2| 4| 5| 7| 9|10|
  508. 2.        1| 4| 7|10|13|16|18|
  509. -----------------------------------
  510. Bb  eb    0| 2| 3| 5| 7| 9|10|
  511. 4.        1| 4| 6|10|13|16|18|
  512. -----------------------------------
  513. Eb  ab    0| 2| 3| 5| 7| 8|10|
  514. 6.        1| 4| 6|10|13|15|18|
  515. -----------------------------------
  516. Ab  db    0| 1| 3| 5| 7| 8|10|
  517. 8.        1| 3| 6|10|13|15|18|
  518. -----------------------------------
  519. Db  gb    0| 1| 3| 5| 6| 8|10|
  520. 10.       1| 3| 6|10|12|15|18|
  521. -----------------------------------
  522. Gb  cb    1| 3| 5| 6| 8|10|11|
  523. 11.       3| 6|10|12|15|18|21|
  524. -----------------------------------
  525. Cb  fb    1| 3| 4| 6| 8|10|11|
  526. 13.       3| 6| 9|12|15|18|21|
  527. -----------------------------------
  528.  
  529. end rem
  530.  

you need the Noten.png from the attachment to run the example.

« Last Edit: June 18, 2021, 13:35:49 by Midimaster »
See my current project on PlayStore: 20Tracks-Audio-Player https://play.google.com/store/apps/details?id=midimaster.twentytrackd

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 736
  • nothing is personal
Re: My Music Editor
« Reply #35 on: June 07, 2021, 21:48:37 »
Thanks midimaster.. I've already experimented with it.. and i will implement it in my code.
I had to fix some Errors of Local I, but other than that it seems to work fine.

I'm not in a mood for programming atm, but ill go back to that soon.
or maybe ill implement it later.. and continue developing other things.
the only way i survive in coding.. is doing what i feel and not doing what i need
...

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 736
  • nothing is personal
Re: My Music Editor
« Reply #36 on: June 10, 2021, 21:03:52 »
MM=MidiMaster..

I tried to implement you method ..into my code.. I didnt succeed too well..
so I went with my system for now..
but I kept you code in Rem State.. in my project..
So I can continue my work..
Ill Contact you again.. soon when Ill solve one more thing and will see what to do
:)

The good news.. Is that Im serious about this App

...

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 736
  • nothing is personal
Re: My Music Editor
« Reply #37 on: June 13, 2021, 22:36:17 »


Im trying to understand the logic of the notation..
and ill try again to implement your code midimaster..

Im looking at muse score app to see how it preforms notations

and ill try again to implement your code..

does your code also support this 3 half tone chords arrangement?

Ive managed to make progress with MidiMaster Code, but im not their yet.

I also Started to like Muse Score..
Finally it makes sense to me

« Last Edit: June 13, 2021, 23:04:46 by Hardcoal »
...

Offline Midimaster

  • Sr. Member
  • ****
  • Posts: 363
    • Midimaster Music Education Software
Re: My Music Editor
« Reply #38 on: June 13, 2021, 23:54:42 »
Also in MuseScore you can see, that the base is not a 12-objects-per-octave-system, but a 21-objects-per-octave-system.

If you want to create a "note object " the property "altitude" of the note needs to be in this 21-system. Re-calculating the midinote from the 21-systems is easy.

but using a 12-system means not beeing able to calculate the correct score position. So there is no way without 21-system.

This is the base, But this is not the final solution for all the problems you will get with notation. So drawing the notes is again a challenge with a lot of rules and still more exeptions.

Using the 21-system means you are able to write all the examples you showed in your screenshot. But these screenshots are no typical notations.

In a perfect notation it would look like this:


Lets talk about the 5 chord in your screenshot:

1. This is allowed. You can combine D,F and G# in one chord. But if it is possible you would always use D-F-Ab. (See my example)

2. perfect

3. This is not allowed what should it be? two C# together with one D? I would write is as one C# with one D.

4. This is not allowed. You never see a Eb and a E written in this way. The solution if you need 3 notes closed together is always to notate it as: D-Eb-Fb (See my example). That is a typical solution where you would use Fb as a replacement for E.

5. Are there 3 note in your example? Not allowed. If this are 2 notes my example would be the solution. If you need again three notes: F-F# and G you would write them always as E#-F#and G

The property, whether a note is notated "normal" or "a little bit to the right" is not a fixed porperty of the note, but a decision of the drawing algorithm in the last moment before displaying it. Often adding one single new note to a chord changes to behavior of all the other members of this chord.

But one rule is: "never use the same altitude position twice". So C-C#-D would always become H#-C#-D.

Or a more complex example: G-G#-A would become a elegant F##-G#-A. The fact that a notation app like muse-score allowes your 5th example still does not mean that it is allowed or elegant.  It is a little bit like writing a typo in WORD: "God Luck" will be printed, but is still a typo.


« Last Edit: June 14, 2021, 00:51:45 by Midimaster »
See my current project on PlayStore: 20Tracks-Audio-Player https://play.google.com/store/apps/details?id=midimaster.twentytrackd

Offline Midimaster

  • Sr. Member
  • ****
  • Posts: 363
    • Midimaster Music Education Software
Re: My Music Editor
« Reply #39 on: June 14, 2021, 00:48:31 »
To your question:

Quote
does your code also support this 3 half tone chords arrangement?
Yes every 21-system does support this! This does not means that the result is alllowed or elegant.

My example code demostrate five things:

1.
How a 21-system works.

2.
How a midi-note is re-calculated from a 21-system-note.

3.
How to calculte a "best match" 21-system-note from a midi note or a midi-chord.

4.
How to display 21-system-notes

5.
How to calcuate the help lines



What is not implemented:

1. It has no algorithm to decide, when placing a note "a little bit to the right". But his can easyly be done by comparing all note of the chord with the given function YPos() (=note/3). If then two results have only a difference of 1 this means you will need this "right displacement" anywhere.

2. It has no a double ## or double bb algorithm. So some of the "3 half tone chords" would look similar unelegant like they do in musescore. (example: G-G#-A)

3. It has no "is it bass or treble"-flag. So this needs to be done.



Write questions if you need more explanation of the example code.


   



« Last Edit: June 14, 2021, 00:56:33 by Midimaster »
See my current project on PlayStore: 20Tracks-Audio-Player https://play.google.com/store/apps/details?id=midimaster.twentytrackd

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 736
  • nothing is personal
Re: My Music Editor
« Reply #40 on: June 16, 2021, 05:04:14 »
I tried putting midi notes 60,61,62 which is C C# and D and your system didnt display it properly..



anyway what I'm gonna do is to post my last version of progress and maybe slowly improve it.. by your advices..

I was busy fixing other stuff in the little time I put on this.
but now, after fixing other errors, I'm free again to concentrate on proper notes displaying.
I promise you ill improve it until it get to what you think its proper, just need patient.

I started making this type of notes Display



And ye .. I know its not correct key. Ill fix.

« Last Edit: June 16, 2021, 05:07:32 by Hardcoal »
...

Offline Midimaster

  • Sr. Member
  • ****
  • Posts: 363
    • Midimaster Music Education Software
Re: My Music Editor
« Reply #41 on: June 16, 2021, 09:25:35 »
The helping line problem does not come from my code.

In the case of 60-61-62 my app crashs, because it is no "senseful chord". The function Notation.WhichTable(MidiChord) returns a "-1", what means: "No table fits!"
In this cases we have to add  "last resort" to pruduce anything but no crash.

I added a new function, which finds those senseless chords and tries to display them in a "all b" or "all #" style. As this can produce notes on the same line, it tries to test both approaches and select the "best". If nothing helps it return a ugly chord with notes onthe same line.

I updated the "Whole Runnable Code" example in my post #34:
https://www.syntaxbomb.com/index.php/topic,8467.msg347050592.html#msg347050592

There the  "Whole Runnable Code" example has now a new function...

Function UseAllSameSign:Int[] (MidiChord:Int[], FlatOrSharp:Int=FLAT)

...which tries to display anything in each situation.

This is the algo:
Code: BlitzMax
  1.         Function UseAllSameSign:Int[] (MidiChord:Int[], FlatOrSharp:Int=FLAT)
  2.                 Global Iteration%
  3.                 ' tricky new function to process also "strange chords"
  4.                 ' if all 14 tables fail this algo trys to prevent notes on the same line
  5.                 Local FlatTableNote[]  =  [1,3,4,6,9,10,12,13,15,16,18,21]
  6.                 Local SharpTableNote[] = [-1,2,4,5,7,8,11,13,14,16,17,19]
  7.                 Local ReturnChord:Int[MidiChord.Length]
  8.                
  9.                 Print "STRANGE CHORD! now Using UseAllSameSign() function with FlatOrSharp=" + FlatOrSharp + " Iteration-Round=" + Iteration
  10.                 ' first use one of the tables:
  11.                 For Local i:Int=0 To MidiChord.Length-1
  12.                         Local SearchNote% = MidiChord[i] Mod 12
  13.                         Local Octave%=MidiChord[i] / 12
  14.                         If FlatOrSharp=SHARP
  15.                                 ReturnChord[i]= SharpTableNote[SearchNote] +21*Octave
  16.                         Else
  17.                                 ReturnChord[i]= FlatTableNote[SearchNote] +21*Octave
  18.                         EndIf
  19.                 Next
  20.                
  21.                 'now test, whether this table also produce notes on the same line:
  22.                         For Local i:Int=0 To MidiChord.Length-1
  23.                                 For Local j:Int=i+1 To MidiChord.Length-1              
  24.                                         If YPos(ReturnChord[i]) = YPos(ReturnChord[j])
  25.                                                 'If yes... try the other table
  26.                                                 If Iteration=0
  27.                                                         Iteration=1  'for not producing a endless loop
  28.                                                         Return UseAllSameSign(MidiChord,1-FlatOrSharp)
  29.                                                 EndIf
  30.                                         EndIf
  31.                                 Next
  32.                         Next
  33.                 Iteration=0
  34.                 Return ReturnChord     
  35.         End Function


Additional I added 2 more tables for the very seldom used scales "C#-Major" with 6#, and "Cb-Major" with 6b. This serves in cases where a F#-Major-Song use the B#-Chord. Or a Gb-Major-Song use the Cb-Chord.


Because my example still has no algo for the "a little bit to the right"problem it now displays the chords in a "arpeggio" style. This makes it easier to check the algo is workuing correct.

Scrennshot shows a 60-61-62-chord
« Last Edit: June 16, 2021, 18:12:36 by Midimaster »
See my current project on PlayStore: 20Tracks-Audio-Player https://play.google.com/store/apps/details?id=midimaster.twentytrackd

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 736
  • nothing is personal
Re: My Music Editor
« Reply #42 on: June 16, 2021, 14:08:34 »
now thats awesome.. im gonna try to use it.. thanks
...

Offline Midimaster

  • Sr. Member
  • ****
  • Posts: 363
    • Midimaster Music Education Software
Re: My Music Editor
« Reply #43 on: June 18, 2021, 13:50:24 »
Ok I again could refine the algo for chords with two improvements.

If all 14 scale-tables fail, now there are 4 additional tables for methods "all with #" and "all with b". both methods now have two steps "less signs" or "a lot of signs":

Code: BlitzMax
  1.         Function UseAllSameSign:Int[] (MidiChord:Int[], Iteration:Int=0)
  2.                 ' tricky new function to process also "strange chords"
  3.                 ' if all 14 tables fail this algo trys to prevent notes on the same line
  4.                 Local SameTableNote[][]= New Int[][4]
  5.                 '                  [C   D   E  F     G     A     B]
  6.                 SameTableNote[0]=  [1,3,4,6,7,10,12,13,15,16,18,19]
  7.                 SameTableNote[1]=  [1,2,4,5,7,10,11,13,14,16,17,19]
  8.                 SameTableNote[2]=  [1,3,4,6,9,10,12,13,15,16,18,21]
  9.                 SameTableNote[3]=  [-1,2,4,5,7,8,11,13,14,16,17,19]
  10.  

The app iterates through al 4 variants and decides for the best.

In the case where all 4 still deliver notes on the same line a new algo UseMixedSigns() starts. It tries to build the chord without any scale-rules only with using any combination of # and b that is theorectical possible:

Code: BlitzMax
  1.         Function UseMixedSigns:Int[] (MidiChord:Int[], BadChord:Int[])
  2.                 ' ultimate chance for chords: Try to mix # with b or send BadChord
  3.                 Local list:TList=New TList
  4.                 Local SearchNote% = MidiChord[0] Mod 12
  5.                 Local Octave%=MidiChord[0] / 12
  6.                 Local locChord:Int[]
  7.                 AddChordsToListe(List, locChord, SearchNote, Octave)
  8.                        
  9.                 For Local i:Int=1 To MidiChord.Length-1
  10.                         Local SearchNote% = MidiChord[i] Mod 12
  11.                         Local Octave%=MidiChord[i] / 12
  12.                
  13.                         For Local Chord:Int[]=EachIn list
  14.                                 If chord.length=i
  15.                                         AddChordsToListe(List, Chord, SearchNote, Octave)
  16.                                         List.Remove Chord
  17.                                 EndIf
  18.                         Next
  19.                 Next
  20.                 Print "EXTREM STRANGE CHORD! now Using UseMixedSigns() function"
  21.                 For Local Chord:Int[]=EachIn list
  22.                         Return chord
  23.                 Next
  24.                 Print "!!!!! BAD CHORD! no solution found !!!!"
  25.                 Return BadChord        
  26.         End Function
  27.  
  28.  
  29.         Function AddChordsToListe(List:TList, Chord[], SearchNote, Octave)
  30.                 Print "Adding " + Searchnote
  31.                 Local last%=Chord.length
  32.                 Local NewChord_I:Int[last+1]
  33.                 Local NewChord_II:Int[last+1]
  34.                 For Local i%=0 To last-1
  35.                         NewChord_I [i] = Chord[i]
  36.                         NewChord_II[i] = Chord[i]
  37.                 Next
  38.                         Select SearchNote
  39.                                 Case 0 
  40.                                         NewChord_I[last]=-1+21*Octave  
  41.                                         NewChord_II[last]=1+21*Octave  
  42.                                 Case 1
  43.                                         NewChord_I[last]=2+21*Octave
  44.                                         NewChord_II[last]=3+21*Octave
  45.                                 Case 2
  46.                                         NewChord_I[last]=4+21*Octave
  47.                                 Case 3
  48.                                         NewChord_I[last]=5+21*Octave
  49.                                         NewChord_II[last]=6+21*Octave          
  50.                                 Case 4
  51.                                         NewChord_I[last]=7+21*Octave
  52.                                         NewChord_II[last]=9+21*Octave                                          
  53.                                 Case 5
  54.                                         NewChord_I[last]=8+21*Octave
  55.                                         NewChord_II[last]=10+21*Octave                                         
  56.                                 Case 6
  57.                                         NewChord_I[last]=11+21*Octave
  58.                                         NewChord_II[last]=12+21*Octave                                                                         
  59.                                 Case 7
  60.                                         NewChord_I[last]=13+21*Octave
  61.                                 Case 8
  62.                                         NewChord_I[last]=14+21*Octave
  63.                                         NewChord_II[last]=15+21*Octave
  64.                                 Case 9
  65.                                         NewChord_I[last]=16+21*Octave                  
  66.                                 Case 10
  67.                                         NewChord_I[last]=17+21*Octave
  68.                                         NewChord_II[last]=18+21*Octave         
  69.                                 Case 11
  70.                                         NewChord_I[last]=19+21*Octave
  71.                                         NewChord_II[last]=21+21*Octave
  72.                         EndSelect
  73.                 If ContainsSameLine(NewChord_I)=False
  74.                         Print "ADD **** Chord_I to list" + StringFromChord(newchord_I)
  75.                         List.Addlast NewChord_I
  76.                 EndIf
  77.                
  78.                 If NewChord_II[Last]>0
  79.                         If ContainsSameLine(NewChord_II)=False
  80.                                 List.AddLast NewChord_II
  81.                                 Print "ADD **** Chord_II to list" + StringFromChord(newchord_II)
  82.                         EndIf
  83.                 EndIf
  84.         End Function
  85.  

In the case where also this algo looses, it decides to take the "Bad-Chord", what means a design of the chord with notes on the same line. This happens f.e. on midichord=67-68-69

I updated for you the The whole runnable example in my post #34. So you have a full running example. It starts with a harmless C-min chord but if you click you can step through all ugly chromatic chord like 59-60-61 then 60-61-62 and so on....

« Last Edit: June 18, 2021, 13:52:14 by Midimaster »
See my current project on PlayStore: 20Tracks-Audio-Player https://play.google.com/store/apps/details?id=midimaster.twentytrackd

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 736
  • nothing is personal
Re: My Music Editor
« Reply #44 on: June 18, 2021, 16:40:41 »
Thanks MidiMaster.. have a nice weekend
Thanks for all the effort youre putting..

From time to time I leave the notation punctuality and concentrating on other aspect of this app.. (when i feel good)
so I wont give it all up.

Now Im working on live notation recording for a while

...

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal