├── _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 |
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 |
3 |
4 |
5 | Jami is not just a musical instrument
6 |
7 |
8 |
9 |
10 |
11 |
12 | [](#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 |
--------------------------------------------------------------------------------