├── _config.yml ├── assets ├── Jami.jpg ├── Jami.png ├── about.png ├── keyboard.jpg ├── screen-1.jpg ├── screen-2.jpg ├── screen-3.jpg └── screen-4.jpg ├── go.mod ├── LICENSE ├── pkg ├── screens │ ├── about.go │ ├── settings.go │ ├── home.go │ └── Keyboard.go └── sound │ ├── sound.go │ └── files.go ├── cmd └── main.go ├── Notes.md ├── README.md └── go.sum /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-tactile -------------------------------------------------------------------------------- /assets/Jami.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehrdad-dev/Jami/HEAD/assets/Jami.jpg -------------------------------------------------------------------------------- /assets/Jami.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehrdad-dev/Jami/HEAD/assets/Jami.png -------------------------------------------------------------------------------- /assets/about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehrdad-dev/Jami/HEAD/assets/about.png -------------------------------------------------------------------------------- /assets/keyboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehrdad-dev/Jami/HEAD/assets/keyboard.jpg -------------------------------------------------------------------------------- /assets/screen-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehrdad-dev/Jami/HEAD/assets/screen-1.jpg -------------------------------------------------------------------------------- /assets/screen-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehrdad-dev/Jami/HEAD/assets/screen-2.jpg -------------------------------------------------------------------------------- /assets/screen-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehrdad-dev/Jami/HEAD/assets/screen-3.jpg -------------------------------------------------------------------------------- /assets/screen-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehrdad-dev/Jami/HEAD/assets/screen-4.jpg -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mehrdad-dev/Jami 2 | 3 | go 1.12 4 | 5 | require ( 6 | fyne.io/fyne v1.2.4 7 | github.com/dbatbold/beep v1.0.1 8 | ) 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 mehrdad mohammadian 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/screens/about.go: -------------------------------------------------------------------------------- 1 | package screens 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | "path/filepath" 7 | 8 | "fyne.io/fyne" 9 | "fyne.io/fyne/canvas" 10 | "fyne.io/fyne/layout" 11 | "fyne.io/fyne/widget" 12 | ) 13 | 14 | func parseURL(urlStr string) *url.URL { 15 | link, err := url.Parse(urlStr) 16 | if err != nil { 17 | fyne.LogError("Could not parse URL", err) 18 | } 19 | 20 | return link 21 | } 22 | 23 | func AboutScreen(a fyne.App) fyne.CanvasObject { 24 | filePath, err := filepath.Abs("../Jami/assets/about.png") 25 | if err != nil { 26 | fmt.Println("ERR in read about.png ", err) 27 | } 28 | 29 | logo := canvas.NewImageFromFile(filePath) 30 | logo.SetMinSize(fyne.NewSize(390, 212)) 31 | 32 | return widget.NewVBox( 33 | widget.NewHBox(layout.NewSpacer(), logo, layout.NewSpacer()), 34 | widget.NewLabelWithStyle("Jami is not just a musical instrument", fyne.TextAlignCenter, fyne.TextStyle{Bold: false}), 35 | 36 | widget.NewHBox(layout.NewSpacer(), 37 | widget.NewHyperlink("github", parseURL("https://github.com/mehrdad-dev")), 38 | widget.NewLabel("-"), 39 | widget.NewHyperlink("contact", parseURL("http://www.mehrdad-dev.ir/contact-me/")), 40 | layout.NewSpacer(), 41 | ), 42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/mehrdad-dev/Jami/pkg/screens" 5 | "os" 6 | 7 | "fyne.io/fyne" 8 | "fyne.io/fyne/app" 9 | "fyne.io/fyne/theme" 10 | "fyne.io/fyne/widget" 11 | ) 12 | 13 | func main() { 14 | a := app.NewWithID("com.jami.app") 15 | a.SetIcon(theme.FyneLogo()) 16 | 17 | w := a.NewWindow("Jami") 18 | w.SetMainMenu(fyne.NewMainMenu( 19 | fyne.NewMenu("Control", 20 | fyne.NewMenuItem("Force Quit", func() { os.Exit(1) }), 21 | ), 22 | fyne.NewMenu( 23 | "View", 24 | fyne.NewMenuItem("Full Screen", func() { w.SetFullScreen(true) }), 25 | fyne.NewMenuItem("Small Screen", func() { w.SetFullScreen(false) }), 26 | ), 27 | ), 28 | ) 29 | w.SetMaster() 30 | 31 | tabs := widget.NewTabContainer( 32 | widget.NewTabItemWithIcon("Home", theme.HomeIcon(), screens.HomeScreen(w)), 33 | widget.NewTabItemWithIcon("Keyboard", theme.MediaPlayIcon(), screens.KeyboardScreen(w)), 34 | widget.NewTabItemWithIcon("Settings", theme.SettingsIcon(), screens.SettingsScreen(a, w)), 35 | widget.NewTabItemWithIcon("About", theme.InfoIcon(), screens.AboutScreen(a))) 36 | 37 | tabs.SetTabLocation(widget.TabLocationBottom) 38 | w.SetContent(tabs) 39 | w.Resize(fyne.NewSize(800, 500)) 40 | // w.SetFixedSize(true) 41 | 42 | w.ShowAndRun() 43 | } 44 | -------------------------------------------------------------------------------- /pkg/sound/sound.go: -------------------------------------------------------------------------------- 1 | package sound 2 | 3 | import ( 4 | "bufio" 5 | "log" 6 | "strings" 7 | "time" 8 | 9 | "github.com/dbatbold/beep" 10 | ) 11 | 12 | // PlayNotes play a string of notes 13 | func PlayNotes(notes string) { 14 | music := beep.NewMusic("") 15 | volume := 100 16 | 17 | if err := beep.OpenSoundDevice("default"); err != nil { 18 | log.Fatal(err) 19 | } 20 | 21 | if err := beep.InitSoundDevice(); err != nil { 22 | log.Fatal(err) 23 | } 24 | 25 | //beep.PrintSheet = true 26 | defer beep.CloseSoundDevice() 27 | 28 | reader := bufio.NewReader(strings.NewReader(notes)) 29 | 30 | go music.Play(reader, volume) 31 | music.Wait() 32 | beep.FlushSoundBuffer() 33 | } 34 | 35 | // SaveNotes save a sound of notes 36 | func SaveNotes(notes string) { 37 | name := time.Now().String() 38 | music := beep.NewMusic("Jami-" + name + ".wav") 39 | volume := 100 40 | 41 | if err := beep.OpenSoundDevice("default"); err != nil { 42 | log.Fatal(err) 43 | } 44 | 45 | if err := beep.InitSoundDevice(); err != nil { 46 | log.Fatal(err) 47 | } 48 | 49 | //beep.PrintSheet = true 50 | defer beep.CloseSoundDevice() 51 | 52 | reader := bufio.NewReader(strings.NewReader(notes)) 53 | 54 | go music.Play(reader, volume) 55 | music.Wait() 56 | beep.FlushSoundBuffer() 57 | } 58 | -------------------------------------------------------------------------------- /pkg/screens/settings.go: -------------------------------------------------------------------------------- 1 | package screens 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mehrdad-dev/Jami/pkg/sound" 6 | "os" 7 | 8 | "fyne.io/fyne" 9 | "fyne.io/fyne/dialog" 10 | "fyne.io/fyne/theme" 11 | "fyne.io/fyne/widget" 12 | "github.com/dbatbold/beep" 13 | ) 14 | 15 | // SettingsScreen return setting canvas 16 | func SettingsScreen(a fyne.App, win fyne.Window) fyne.CanvasObject { 17 | music := beep.NewMusic("") 18 | buttonDownload := widget.NewButtonWithIcon("Download files", theme.CheckButtonCheckedIcon(), 19 | func() { 20 | prog := dialog.NewProgressInfinite("Download and Saving Files", 21 | "Please wait...", win) 22 | 23 | go func() { 24 | err := sound.DownloadVoiceFiles(music, os.Stdout, []string{}) 25 | if err != nil { 26 | fmt.Println("ERR in download files: ", err) 27 | } 28 | prog.Hide() 29 | }() 30 | 31 | prog.Show() 32 | }) 33 | 34 | return widget.NewVBox( 35 | widget.NewLabelWithStyle("Change Theme", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), 36 | widget.NewSelect([]string{"Dark Theme", "Light Theme"}, func(s string) { 37 | if s == "Dark Theme" { 38 | a.Settings().SetTheme(theme.DarkTheme()) 39 | } else { 40 | a.Settings().SetTheme(theme.LightTheme()) 41 | } 42 | }), 43 | widget.NewLabelWithStyle("Download piano and violin sounds", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), 44 | widget.NewLabel("For download press button and wait"), 45 | buttonDownload, 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /pkg/sound/files.go: -------------------------------------------------------------------------------- 1 | package sound 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "io/ioutil" 7 | "net/http" 8 | "os" 9 | "path/filepath" 10 | "strings" 11 | 12 | "github.com/dbatbold/beep" 13 | ) 14 | 15 | // DownloadVoiceFiles downloads natural voice files 16 | func DownloadVoiceFiles(music *beep.Music, writer io.Writer, names []string) error { 17 | dir := filepath.Join(beep.HomeDir(), "voices") 18 | if len(names) == 0 { 19 | names = []string{"piano", "violin"} 20 | } 21 | for _, name := range names { 22 | if !strings.HasSuffix(name, ".zip") { 23 | name += ".zip" 24 | } 25 | url := "http://bmrust.com/dl/beep/voices/" + name 26 | 27 | // locate file 28 | resp, err := http.Head(url) 29 | if err != nil { 30 | return err 31 | } 32 | if resp.StatusCode != http.StatusOK { 33 | return err 34 | } 35 | 36 | // fetch file 37 | resp, err = http.Get(url) 38 | fmt.Println("start Download ...", name) 39 | if err != nil { 40 | return err 41 | } 42 | if resp.StatusCode != http.StatusOK { 43 | return err 44 | } 45 | defer resp.Body.Close() 46 | 47 | // read file 48 | body, err := ioutil.ReadAll(resp.Body) 49 | fmt.Println("end Download ...", name) 50 | if err != nil { 51 | return err 52 | } 53 | 54 | // save file 55 | os.MkdirAll(dir, 0755) 56 | filename := filepath.Join(dir, name) 57 | err = ioutil.WriteFile(filename, body, 0644) 58 | if err != nil { 59 | return err 60 | } 61 | 62 | fmt.Fprintf(writer, "files Saving %s\n", filename) 63 | } 64 | 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /Notes.md: -------------------------------------------------------------------------------- 1 | ## ➤ Notes 2 | 3 | You can see all keys that have a sound in keyboard: 4 |

5 | MeiliSearch 6 |

7 | 8 | And also all keywords for write notes: 9 | 10 | ```` 11 | Left and right hand keys are same. Uppercase 12 | letters are control keys. Lowercase letters 13 | are music notes. Space bar is current duration 14 | rest. Spaces after first space are ignored. 15 | Lines start with '#' are ignored. 16 | 17 | Control keys: 18 | 19 | Rest: 20 | RW - whole rest 21 | RH - half rest 22 | RQ - quarter rest 23 | RE - eighth rest 24 | RS - sixteenth rest 25 | RT - thirty-second rest 26 | RI - sixty-fourth rest 27 | 28 | Durations: 29 | DW - whole note 30 | DH - half note 31 | DQ - quarter note 32 | DE - eighth note 33 | DS - sixteenth note 34 | DT - thirty-second note 35 | DI - sixty-fourth note 36 | DD - dotted note (adds half duration) 37 | 38 | Octave: 39 | H0 - octave 0 keys 40 | HL - octave 1, 2, 3 (left hand keys) 41 | HR - octave 4, 5, 6 (right hand keys) 42 | H7 - octave 7, 8 keys 43 | 44 | Tempo: 45 | T# - where # is 0-9, default is 4 46 | 47 | Sustain: 48 | SA# - attack level, where # is 0-9, default is 8 49 | SD# - decay level, 0-9, default 4 50 | SS# - sustain level, 0-9, default 4 51 | SR# - release level, 0-9, default 9 52 | 53 | Voice: 54 | VD - Computer generated default voice 55 | VP - Piano voice 56 | VV - Violin voice (WIP) 57 | VN - If a line ends with 'VN', the next line will be played 58 | harmony with the line. 59 | 60 | Chord: 61 | C# - Play next # notes as a chord, where # is 2-9. 62 | For example C major chord is "C3qet" 63 | 64 | Amplitude: 65 | A# - Changes current amplitude, where # is 1-9, default is 9 66 | 67 | Measures: 68 | | - bar, ignored 69 | ' ' - space, ignored 70 | Tab - tab, ignored 71 | 72 | Comments: 73 | # - a line comment 74 | ## - start or end of a block comment 75 | ```` -------------------------------------------------------------------------------- /pkg/screens/home.go: -------------------------------------------------------------------------------- 1 | package screens 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mehrdad-dev/Jami/pkg/sound" 6 | 7 | "fyne.io/fyne" 8 | "fyne.io/fyne/layout" 9 | "fyne.io/fyne/theme" 10 | "fyne.io/fyne/widget" 11 | ) 12 | 13 | func makeHome(win fyne.Window) fyne.Widget { 14 | var soundSTR string 15 | 16 | // Create sound selector 17 | soundSelector := widget.NewSelect([]string{"Piano", "Violin", "System"}, func(s string) { 18 | if s == "Piano" { 19 | soundSTR = "VP SA9 SR9\n" 20 | } else if s == "Violin" { 21 | soundSTR = "VV SA9 SR9\n" 22 | } else { 23 | soundSTR = "VD SA9 SR9\n" 24 | } 25 | }) 26 | 27 | // Create input form 28 | notesInput := widget.NewMultiLineEntry() 29 | notesInput.SetPlaceHolder("Fill with notes") 30 | form := &widget.Form{ 31 | OnSubmit: func() { 32 | sound.PlayNotes(soundSTR + notesInput.Text) 33 | }, 34 | } 35 | form.Append("Notes", notesInput) 36 | 37 | buttonSave := widget.NewButtonWithIcon("Save notes sound in .wav file", theme.DocumentSaveIcon(), 38 | func() { 39 | sound.SaveNotes(soundSTR + notesInput.Text) 40 | }) 41 | 42 | return widget.NewGroupWithScroller("Home Page", 43 | widget.NewLabelWithStyle("Select Instrument", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), 44 | soundSelector, 45 | buttonSave, 46 | form, 47 | ) 48 | } 49 | 50 | func makeKeyboardTab() fyne.Widget { 51 | list2 := widget.NewHBox() 52 | 53 | for i := 1; i <= 8; i++ { 54 | index := i 55 | button := widget.NewButton(fmt.Sprintf("Button %d", index), func() { 56 | fmt.Println("Tapped", index) 57 | }) 58 | button.Resize(fyne.NewSize(50, 50)) 59 | list2.Append(button) 60 | } 61 | return widget.NewVBox( 62 | widget.NewLabelWithStyle("\nEnter notes from keyboard", fyne.TextAlignCenter, fyne.TextStyle{Bold: true}), 63 | list2, 64 | ) 65 | } 66 | 67 | // HomeScreen create home screen 68 | func HomeScreen(win fyne.Window) fyne.CanvasObject { 69 | return fyne.NewContainerWithLayout(layout.NewAdaptiveGridLayout(1), 70 | makeHome(win), 71 | // widget.NewTabContainer( 72 | // widget.NewTabItem("Notes", makeNoteTab(win)), 73 | // // widget.NewTabItem("Keyboard", makeKeyboardTab()), 74 | // ), 75 | ) 76 | } 77 | -------------------------------------------------------------------------------- /pkg/screens/Keyboard.go: -------------------------------------------------------------------------------- 1 | package screens 2 | 3 | import ( 4 | "github.com/mehrdad-dev/Jami/pkg/sound" 5 | 6 | "fyne.io/fyne" 7 | "fyne.io/fyne/layout" 8 | "fyne.io/fyne/widget" 9 | ) 10 | 11 | func createButton(win fyne.Window, textArray string) fyne.CanvasObject { 12 | if textArray == "" { 13 | return layout.NewSpacer() 14 | } 15 | button := widget.NewButton(textArray, func() { 16 | sound.PlayNotes(textArray) 17 | win.Canvas().SetOnTypedRune(func(r rune) { 18 | sound.PlayNotes("VP SA9 SR9\n" + string(r)) 19 | }) 20 | }) 21 | return button 22 | } 23 | 24 | // KeyboardScreen create Keyboard screen 25 | func KeyboardScreen(win fyne.Window) fyne.CanvasObject { 26 | return fyne.NewContainerWithLayout(layout.NewGridLayout(1), 27 | fyne.NewContainerWithLayout(layout.NewGridLayout(9)), 28 | fyne.NewContainerWithLayout(layout.NewGridLayout(9)), 29 | fyne.NewContainerWithLayout(layout.NewGridLayout(9)), 30 | fyne.NewContainerWithLayout(layout.NewGridLayout(9)), 31 | fyne.NewContainerWithLayout(layout.NewGridLayout(11), 32 | createButton(win, "2"), 33 | createButton(win, "3"), 34 | createButton(win, ""), 35 | createButton(win, "5"), 36 | createButton(win, "6"), 37 | createButton(win, "7"), 38 | createButton(win, ""), 39 | createButton(win, "9"), 40 | createButton(win, "0"), 41 | createButton(win, ""), 42 | createButton(win, "="), 43 | ), 44 | fyne.NewContainerWithLayout(layout.NewGridLayout(12), 45 | createButton(win, "q"), 46 | createButton(win, "w"), 47 | createButton(win, "e"), 48 | createButton(win, "r"), 49 | createButton(win, "t"), 50 | createButton(win, "y"), 51 | createButton(win, "u"), 52 | createButton(win, "i"), 53 | createButton(win, "o"), 54 | createButton(win, "p"), 55 | createButton(win, "["), 56 | createButton(win, "]"), 57 | ), 58 | fyne.NewContainerWithLayout(layout.NewGridLayout(9), 59 | createButton(win, "a"), 60 | createButton(win, "s"), 61 | createButton(win, ""), 62 | createButton(win, "f"), 63 | createButton(win, "g"), 64 | createButton(win, ""), 65 | createButton(win, "j"), 66 | createButton(win, "k"), 67 | createButton(win, "l"), 68 | ), 69 | fyne.NewContainerWithLayout(layout.NewGridLayout(9), 70 | createButton(win, "z"), 71 | createButton(win, "x"), 72 | createButton(win, "c"), 73 | createButton(win, "v"), 74 | createButton(win, "b"), 75 | createButton(win, "n"), 76 | createButton(win, "m"), 77 | createButton(win, ","), 78 | createButton(win, "."), 79 | ), 80 | fyne.NewContainerWithLayout(layout.NewGridLayout(9)), 81 | ) 82 | } 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | jami 3 |

4 | 5 |

Jami is not just a musical instrument

6 | 7 | 8 |

9 | License 10 |

11 | 12 | [![-----------------------------------------------------](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png)](#table-of-contents) 13 |
14 |
15 | 16 | ## ➤ What is Jami? 17 | Jami is a simple cross-platform GUI for playing some musical instruments. 18 |
19 |
20 | ✌️ Now you can see Jami in: [fyne apps list](https://apps.fyne.io/) 21 | 22 | ## ➤ Who is Jami? 23 | Jami is an Iranian poet, musician and writer 24 | He is the most famous Persian poet of the ninth century AH. 25 | 26 | And this name has been chosen to commemorate his name. 27 |
28 |
29 | ## ➤ Screens 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | You can see screens in Jami. 47 | 48 | Jami have dark and light theme. 49 |
50 |
51 | ## ➤ How to use? 52 | Just download latest release and then run. 53 | 54 | ❌ Important Notice: 55 | 56 | When you download and run the app, first you need to go to the settings tab and press the download button for download natural sounds. 57 | if you don't this work the app plays notes with system sound. 58 | 59 | ## ➤ Download Jami 60 | Go to the release page and download Jami for your OS: [release page](https://github.com/mehrdad-dev/Jami/releases) 61 |
62 |
63 | ## ➤ Demo music 64 | Copy this and then paste in note input. 65 | ```` 66 | A9HRDE cc DScszs|DEc DQzDE[|cc DScszs|DEc DQz DE[|vv DSvcsc|DEvs ]v|cc DScszs|VN 67 | A3HLDE [n z, |cHRq HLz, |[n z, |cHRq HLz, |sl z, |]m pb|z, ]m | 68 | 69 | A9HRDE cz [c|ss DSsz]z|DEs] ps|DSsz][ z][p|DEpDQ[ [|VN 70 | A3HLDE [n ov|]m [n | pb ic| n, lHRq|HLnc DQ[| 71 | 72 | A9HRDE cc DScszs|DEc DQzDE[|cc DScszs|DEc DQz DE[|vv DSvcsc|DEvs ]v|cc DScszs|VN 73 | A3HLDE [n z, |cHRq HLz, |[n z, |cHRq HLz, |sl z, |]m pb|z, ]m | 74 | 75 | A9HRDE cz [c|ss DSsz]z|DEs] ps|DSsz][ z][p|DEpDQ[ [|VN 76 | A3HLDE [n ov|]m [n | pb ic| n, lHRq|HLnc DQ[| 77 | ```` 78 | 79 | ## ➤ How to write notes? 80 | You can read docs in below link: 81 | 82 | 1- [About notes and keywords](https://github.com/mehrdad-dev/Jami/blob/master/Notes.md) 83 | 84 | 85 | This section will be completed in the future. 86 |
87 |
88 | ## ➤ Roadmap for v2.0 89 | 90 | - [ ] Add new themes 91 | - [X] Add piano keyboard tab 92 | - [X] Add save music in .wav file 93 | - [ ] Add other musical instrument 94 | - [ ] Complete the documents 95 | - [X] Fix scroll on the home page 96 | - [ ] Fix delay in keyboard input 97 | - [ ] Fix the app icon and picture 98 | 99 | 100 | 101 | ## ➤ What does Jami use? 102 | Jami uses these libraries: 103 | 104 | 1- [fyne: Cross-platform GUI in Go based on Material Design](https://github.com/fyne-io/fyne) 105 | 106 | 2- [beep: Beep sound library and utility for alerting end of a command execution](https://github.com/dbatbold/beep) 107 |
108 |
109 | ## ➤ Contribute 110 | 111 | You can send an email to me or create an issue. 112 | 113 | mail: mehrdad.mhmdn@gmail.com 114 |
115 |
116 | ## ➤ Licence 117 | [MIT Licence](https://github.com/mehrdad-dev/Jami/blob/master/LICENSE) 118 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | fyne.io/fyne v1.2.3/go.mod h1:JhDdBrPP/Kdr1H5ZT3HW8E/6zlz+GkOldWqSirGBDnY= 2 | fyne.io/fyne v1.2.4 h1:QN5GQEZ9FANvFxkIQLQ5qnmmpSwBAoDiH8hQiuz2Zyo= 3 | fyne.io/fyne v1.2.4/go.mod h1:nsGex1XH/8p/kq6KiQV4bNu0XTKaFJRbZEOOj4fqJF8= 4 | github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= 5 | github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= 6 | github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= 7 | github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I= 8 | github.com/ably/ably-go v1.1.3 h1:HRIJ56k3SfgnVxdaMMyNg6PntiMHIfpYSkLjdV8WOLA= 9 | github.com/ably/ably-go v1.1.3/go.mod h1:bdOnFcqJrbZE7WSp1jqbdsIMBo5aMGXh98GWiiwmeZ0= 10 | github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= 11 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 12 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 13 | github.com/dbatbold/beep v1.0.1 h1:hcCPZenFTLl0C9i+irSVLy6sCtmBFX2nfJxAqHlKGLU= 14 | github.com/dbatbold/beep v1.0.1/go.mod h1:nCYglCMeZFCH+ufNXeSjJ5JXN69g8gTPKmCLFBt5zL4= 15 | github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= 16 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 17 | github.com/fyne-io/examples v0.0.0-20200402112823-943eb2353915 h1:cuGCn68Y4UDcb6EnpR+lQQCXLe4M7azl7vYNA7JKPKo= 18 | github.com/fyne-io/examples v0.0.0-20200402112823-943eb2353915/go.mod h1:u9Z/Bj7V6MIS+Nntf0ardfGWOenElQnP3I4/HyZ5VUg= 19 | github.com/fyne-io/mobile v0.0.1 h1:Skc/XcZy1ZNdBanhZB9D8114fU4K+kSi5QZXuG6JPeQ= 20 | github.com/fyne-io/mobile v0.0.1/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY= 21 | github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= 22 | github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= 23 | github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw= 24 | github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= 25 | github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f h1:7MsFMbSn8Lcw0blK4+NEOf8DuHoOBDhJsHz04yh13pM= 26 | github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 27 | github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8= 28 | github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= 29 | github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc= 30 | github.com/josephspurrier/goversioninfo v0.0.0-20190124120936-8611f5a5ff3f/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE= 31 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 32 | github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= 33 | github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 34 | github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= 35 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 36 | github.com/mum4k/termdash v0.12.0 h1:K7PXrv5Lk+qk8PnVJJ04LFAE87MXV7fYxzRKrgrx4t8= 37 | github.com/mum4k/termdash v0.12.0/go.mod h1:haerPCSO0U8pehROAecmuOHDF+2UXw2KaCTxdWooDFE= 38 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= 39 | github.com/nsf/termbox-go v0.0.0-20200204031403-4d2b513ad8be/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= 40 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 41 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 42 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 43 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 44 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 45 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 46 | github.com/srwiley/oksvg v0.0.0-20190829233741-58e08c8fe40e/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4= 47 | github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQOVpMmj5MQnGnv+e8uZNu3xFLgyM= 48 | github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4= 49 | github.com/srwiley/rasterx v0.0.0-20181219215540-696f7edb7a7e h1:FFotfUvew9Eg02LYRl8YybAnm0HCwjjfY5JlOI1oB00= 50 | github.com/srwiley/rasterx v0.0.0-20181219215540-696f7edb7a7e/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= 51 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 52 | github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709 h1:Ko2LQMrRU+Oy/+EDBwX7eZ2jp3C47eDBB8EIhKTun+I= 53 | github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 54 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 55 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 56 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= 57 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 58 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 59 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 60 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 61 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 62 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 63 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 64 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= 65 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 66 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 67 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 68 | golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 69 | golang.org/x/net v0.0.0-20190110200230-915654e7eabc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 70 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 71 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= 72 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 73 | golang.org/x/net v0.0.0-20191204025024-5ee1b9f4859a h1:+HHJiFUXVOIS9mr1ThqkQD1N8vpFCfCShqADBM12KTc= 74 | golang.org/x/net v0.0.0-20191204025024-5ee1b9f4859a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 75 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 76 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 77 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 78 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 79 | golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 80 | golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= 81 | golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 82 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 83 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 84 | golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 85 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 86 | golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 87 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 88 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 89 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 90 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 91 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 92 | --------------------------------------------------------------------------------